using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Text;
using System.Windows.Forms;
using System.Management;
using System.Runtime.InteropServices;
using IppServer.Host.Configuration;
using IppServer.Host.Printing;
using IppServer.Host.TcpRaw;
using Microsoft.Win32;
using System.Reflection;

namespace IppServer.Host.Ui
{
    internal sealed class MainForm : Form
    {
        private readonly BindingList<string> _installedPrinters = new BindingList<string>();
        private BindingList<PrinterMapping> _printerMappings;

        private readonly TabControl _tabControl = new TabControl();
        private readonly TabPage _configTab = new TabPage("IPP打印服务");
        private readonly TabPage _tcpTab = new TabPage("TCP端口服务");
        private readonly TabPage _logTab = new TabPage("运行日志");
        private readonly TabPage _restrictionTab = new TabPage("IP/MAC限制");
        private readonly TabPage _aboutTab = new TabPage("关于");
        private readonly ComboBox _interfaceCombo = new ComboBox();
        private readonly Button _refreshInterfacesButton = new Button();
        private readonly NumericUpDown _portInput = new NumericUpDown();
        private readonly TextBox _pathTextBox = new TextBox();
        private readonly Label _effectiveUrlLabel = new Label();
        private readonly ListBox _installedPrintersListBox = new ListBox();
        private readonly TextBox _queueNameTextBox = new TextBox();
        private readonly Button _refreshPrintersButton = new Button();
        private readonly Button _addMappingButton = new Button();
        private readonly Button _removeMappingButton = new Button();
        private readonly DataGridView _mappingGrid = new DataGridView();
        private readonly DataGridView _tcpTaskGrid = new DataGridView();
        private readonly Button _tcpAddButton = new Button();
        private readonly Button _tcpRemoveButton = new Button();
        private readonly Button _tcpStartButton = new Button();
        private readonly Button _tcpStopButton = new Button();
        private readonly CheckBox _enableTcpServiceCheckBox = new CheckBox();
        private readonly Label _tcpStatusLabel = new Label();
        private readonly Button _startButton = new Button();
        private readonly Button _stopButton = new Button();
        private readonly Button _saveButton = new Button();
        private readonly Button _installServiceButton = new Button();
        private readonly CheckBox _autoStartCheckBox = new CheckBox();
        private readonly CheckBox _runOnBootCheckBox = new CheckBox();
        private readonly CheckBox _enableMdnsCheckBox = new CheckBox();
        private readonly Label _statusLabel = new Label();
        private readonly Label _sharedStatusLabel = new Label();
        private readonly RichTextBox _logTextBox = new RichTextBox();
        private readonly Button _clearLogButton = new Button();
        private readonly BindingList<InterfaceOption> _interfaceOptions = new BindingList<InterfaceOption>();
        private bool _isUpdatingNetworkInputs;
        private DataGridViewComboBoxColumn _printerComboColumn;
        private DataGridViewComboBoxColumn _tcpPrinterComboColumn;
        private DataGridViewComboBoxColumn _tcpModeComboColumn;
        private bool _queueNameDirty;
        private bool _suppressQueueSuggestion;
        private bool _initializingOptions;
        private NotifyIcon _trayIcon;
        private ContextMenuStrip _trayMenu;
        private ToolStripMenuItem _trayStartMenuItem;
        private ToolStripMenuItem _trayStopMenuItem;
        private readonly bool _launchedFromAutorun;
        private bool _trayBalloonShown;
        private Icon _appIcon;
        private const string AutoRunRegistryValue = "IPPServerHost";

        private AppSettings _settings;
        private IppServerHost _host;
        private Tcp9100PrintServer _tcpServer;
        private System.IO.FileSystemWatcher _configWatcher;
        private bool _isReloadingConfig;
        private BindingList<TcpPrinterTask> _tcpTasks;
        private bool _suppressAutoSave;
        private readonly HostBasedPrinterDetector _hostPrinterDetector = new HostBasedPrinterDetector();
        private string _lastTcpPrinterSelection = string.Empty;
        
        // IP/MAC限制管理控件
        private readonly CheckBox _enableRestrictionCheckBox = new CheckBox();
        private readonly RadioButton _whitelistRadioButton = new RadioButton();
        private readonly RadioButton _blacklistRadioButton = new RadioButton();
        private readonly DataGridView _ipRulesGrid = new DataGridView();
        private readonly DataGridView _macRulesGrid = new DataGridView();
        private readonly Button _addIpRuleButton = new Button();
        private readonly Button _removeIpRuleButton = new Button();
        private readonly Button _addMacRuleButton = new Button();
        private readonly Button _removeMacRuleButton = new Button();
        private readonly BindingList<string> _ipRulesList = new BindingList<string>();
        private readonly BindingList<string> _macRulesList = new BindingList<string>();

        public MainForm(bool launchedFromAutorun = false)
        {
            _launchedFromAutorun = launchedFromAutorun;
            Text = "IPP Server 管理控制台";
            Width = 900;
            Height = 640;
            Font = new System.Drawing.Font("Segoe UI", 9F);
            BackColor = System.Drawing.Color.WhiteSmoke;
            FormBorderStyle = FormBorderStyle.FixedDialog;
            MaximizeBox = false;

            _settings = AppSettingsStore.Load();
            _suppressAutoSave = true;
            SetPrinterMappingsList(new BindingList<PrinterMapping>(_settings.PrinterMappings ?? new List<PrinterMapping>()));
            SetTcpTaskList(new BindingList<TcpPrinterTask>(_settings.TcpPrinterTasks ?? new List<TcpPrinterTask>()));
            _suppressAutoSave = false;
            _tcpServer = new Tcp9100PrintServer(AppendLog);
            
            // 如果未设置管理员密码，创建初始化令牌（允许GUI首次设置密码）
            if (string.IsNullOrEmpty(_settings.AdminPasswordHash))
            {
                if (!Configuration.AdminPasswordInitializer.IsInitialized())
                {
                    Configuration.AdminPasswordInitializer.CreateInitToken();
                    AppendLog("提示：未设置管理员密码，Web管理界面已锁定。请在GUI中设置管理员密码。");
                }
            }

            LoadApplicationIcon();
            InitializeLayout();
            InitializeTrayIcon();
            LoadNetworkInterfaceOptions();
            BindData();
            WireEvents();
            LoadInstalledPrinters();
            InitializeOptionStates();
            InitializeConfigWatcher();
            TryAutoStartServiceOnLaunch();
        }
        
        private void InitializeConfigWatcher()
        {
            try
            {
                // 与 AppSettingsStore 使用相同的配置文件路径（%ProgramData%\IppServer\appsettings.json）
                var configPath = Configuration.AppSettingsStore.GetPath();
                var configDir = System.IO.Path.GetDirectoryName(configPath);
                var configFile = System.IO.Path.GetFileName(configPath);
                
                _configWatcher = new System.IO.FileSystemWatcher(configDir, configFile)
                {
                    NotifyFilter = System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.Size,
                    EnableRaisingEvents = true
                };
                
                _configWatcher.Changed += (sender, e) =>
                {
                    // 延迟一下，避免文件还在写入时读取
                    System.Threading.Thread.Sleep(100);
                    
                    // 确保在UI线程中执行
                    if (InvokeRequired)
                    {
                        Invoke(new System.Action(() => ReloadConfigFromFile()));
                    }
                    else
                    {
                        ReloadConfigFromFile();
                    }
                };
            }
            catch (Exception ex)
            {
                AppendLog($"初始化配置文件监控失败：{ex.Message}");
            }
        }
        
        private void ReloadConfigFromFile()
        {
            if (_isReloadingConfig)
            {
                return; // 避免重复加载
            }
            
            try
            {
                _isReloadingConfig = true;

                var newSettings = AppSettingsStore.Load();

                if (!AreSettingsEqual(_settings, newSettings))
                {
                    ExecuteWithAutoSaveSuspended(() =>
                    {
                        _settings = newSettings;
                        SetPrinterMappingsList(new BindingList<PrinterMapping>(_settings.PrinterMappings ?? new List<PrinterMapping>()));
                        SetTcpTaskList(new BindingList<TcpPrinterTask>(_settings.TcpPrinterTasks ?? new List<TcpPrinterTask>()));

                        BindData();
                        LoadNetworkInterfaceOptions();
                        InitializeOptionStates();
                    });

                    if (_host != null)
                    {
                        var displayPrefix = NormalizeBasePrefixForDisplay(_settings.BasePrefix);
                        UpdateStatus(true, displayPrefix);
                    }

                    AppendLog("检测到配置文件已更新，已自动刷新界面");
                }
            }
            catch (Exception ex)
            {
                AppendLog($"重新加载配置失败：{ex.Message}");
            }
            finally
            {
                _isReloadingConfig = false;
            }
        }
        
        private bool AreSettingsEqual(AppSettings s1, AppSettings s2)
        {
            if (s1 == null || s2 == null)
            {
                return s1 == s2;
            }
            
            if (s1.BasePrefix != s2.BasePrefix)
            {
                return false;
            }

            if (s1.EnableTcp9100Service != s2.EnableTcp9100Service)
            {
                return false;
            }
            
            // 比较IP/MAC限制设置
            if (!AreIpMacRestrictionsEqual(s1.IpMacRestriction, s2.IpMacRestriction))
            {
                return false;
            }
            
            if (s1.PrinterMappings == null && s2.PrinterMappings == null)
            {
                return true;
            }
            
            if (s1.PrinterMappings == null || s2.PrinterMappings == null)
            {
                return false;
            }
            
            if (s1.PrinterMappings.Count != s2.PrinterMappings.Count)
            {
                return false;
            }
            
            var mappings1 = s1.PrinterMappings.OrderBy(m => m.QueueName).ThenBy(m => m.PrinterName).ToList();
            var mappings2 = s2.PrinterMappings.OrderBy(m => m.QueueName).ThenBy(m => m.PrinterName).ToList();
            
            for (int i = 0; i < mappings1.Count; i++)
            {
                if (mappings1[i].QueueName != mappings2[i].QueueName ||
                    mappings1[i].PrinterName != mappings2[i].PrinterName)
                {
                    return false;
                }
            }
            
            return AreTcpTasksEqual(s1.TcpPrinterTasks, s2.TcpPrinterTasks);
        }
        
        private static bool AreIpMacRestrictionsEqual(Configuration.IpMacRestriction r1, Configuration.IpMacRestriction r2)
        {
            if (r1 == null && r2 == null)
            {
                return true;
            }
            
            if (r1 == null || r2 == null)
            {
                return false;
            }
            
            if (r1.Enabled != r2.Enabled)
            {
                return false;
            }
            
            if (r1.WhitelistMode != r2.WhitelistMode)
            {
                return false;
            }
            
            // 比较IP规则
            if (r1.IpRules == null && r2.IpRules == null)
            {
                // 继续比较MAC规则
            }
            else if (r1.IpRules == null || r2.IpRules == null)
            {
                return false;
            }
            else if (r1.IpRules.Count != r2.IpRules.Count)
            {
                return false;
            }
            else
            {
                var rules1 = r1.IpRules.OrderBy(r => r).ToList();
                var rules2 = r2.IpRules.OrderBy(r => r).ToList();
                for (int i = 0; i < rules1.Count; i++)
                {
                    if (rules1[i] != rules2[i])
                    {
                        return false;
                    }
                }
            }
            
            // 比较MAC规则
            if (r1.MacRules == null && r2.MacRules == null)
            {
                return true;
            }
            
            if (r1.MacRules == null || r2.MacRules == null)
            {
                return false;
            }
            
            if (r1.MacRules.Count != r2.MacRules.Count)
            {
                return false;
            }
            
            var macRules1 = r1.MacRules.OrderBy(r => r).ToList();
            var macRules2 = r2.MacRules.OrderBy(r => r).ToList();
            for (int i = 0; i < macRules1.Count; i++)
            {
                if (macRules1[i] != macRules2[i])
                {
                    return false;
                }
            }
            
            return true;
        }

        private static bool AreTcpTasksEqual(List<TcpPrinterTask> first, List<TcpPrinterTask> second)
        {
            if ((first == null || first.Count == 0) && (second == null || second.Count == 0))
            {
                return true;
            }

            if (first == null || second == null)
            {
                return false;
            }

            if (first.Count != second.Count)
            {
                return false;
            }

            var ordered1 = first.OrderBy(t => t.Port)
                .ThenBy(t => t.PrinterName ?? string.Empty, StringComparer.OrdinalIgnoreCase)
                .ThenBy(t => t.PrintMode ?? string.Empty, StringComparer.OrdinalIgnoreCase)
                .ToList();

            var ordered2 = second.OrderBy(t => t.Port)
                .ThenBy(t => t.PrinterName ?? string.Empty, StringComparer.OrdinalIgnoreCase)
                .ThenBy(t => t.PrintMode ?? string.Empty, StringComparer.OrdinalIgnoreCase)
                .ToList();

            for (int i = 0; i < ordered1.Count; i++)
            {
                if (!string.Equals(ordered1[i].PrinterName, ordered2[i].PrinterName, StringComparison.OrdinalIgnoreCase) ||
                    !string.Equals(ordered1[i].PrintMode, ordered2[i].PrintMode, StringComparison.OrdinalIgnoreCase) ||
                    ordered1[i].Port != ordered2[i].Port)
                {
                    return false;
                }
            }

            return true;
        }

        private void InitializeLayout()
        {
            var rootLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                Padding = new Padding(0),
                BackColor = System.Drawing.Color.White
            };
            rootLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            // 底部状态栏高度控制得更紧凑一些
            rootLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 32));

            _tabControl.Dock = DockStyle.Fill;
            rootLayout.Controls.Add(_tabControl, 0, 0);
            rootLayout.Controls.Add(CreateSharedStatusPanel(), 0, 1);
            Controls.Add(rootLayout);

            var mainLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 3,
                Padding = new Padding(12),
                BackColor = System.Drawing.Color.White
            };
            mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 190));
            mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 60));

            mainLayout.Controls.Add(CreateListenerGroup(), 0, 0);
            mainLayout.Controls.Add(CreateSharingGroup(), 0, 1);
            mainLayout.Controls.Add(CreateActionsPanel(), 0, 2);

            _configTab.Padding = new Padding(3);
            _configTab.Controls.Add(mainLayout);
            _tabControl.TabPages.Add(_configTab);

            InitializeTcpTab();
            InitializeRestrictionTab();
            InitializeLogTab();
            InitializeAboutTab();
        }

        private Control CreateListenerGroup()
        {
            var group = new GroupBox
            {
                Text = "监听设置",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 3,
                RowCount = 4,
                Padding = new Padding(10, 8, 10, 8)
            };
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 34));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 34));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 34));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

            layout.Controls.Add(new Label { Text = "监听网卡：", TextAlign = System.Drawing.ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, 0);
            _interfaceCombo.DropDownStyle = ComboBoxStyle.DropDownList;
            _interfaceCombo.Dock = DockStyle.Fill;
            layout.Controls.Add(_interfaceCombo, 1, 0);

            _refreshInterfacesButton.Text = "刷新网卡";
            _refreshInterfacesButton.Width = 100;
            layout.Controls.Add(_refreshInterfacesButton, 2, 0);

            layout.Controls.Add(new Label { Text = "监听端口：", TextAlign = System.Drawing.ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, 1);
            _portInput.Minimum = 1;
            _portInput.Maximum = 65535;
            _portInput.Value = 8631;
            _portInput.Dock = DockStyle.Left;
            _portInput.Width = 120;
            layout.Controls.Add(_portInput, 1, 1);
            layout.Controls.Add(new Label { Text = "范围 1 - 65535", TextAlign = System.Drawing.ContentAlignment.MiddleLeft, Dock = DockStyle.Fill }, 2, 1);

            layout.Controls.Add(new Label { Text = "访问路径：", TextAlign = System.Drawing.ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, 2);
            _pathTextBox.Text = "/printers/";
            _pathTextBox.Dock = DockStyle.Fill;
            layout.SetColumnSpan(_pathTextBox, 2);
            layout.Controls.Add(_pathTextBox, 1, 2);

            layout.Controls.Add(new Label { Text = "示例地址：", TextAlign = System.Drawing.ContentAlignment.MiddleRight, Dock = DockStyle.Fill }, 0, 3);
            _effectiveUrlLabel.AutoSize = true;
            _effectiveUrlLabel.Text = "HTTP: http://0.0.0.0:8631/printers/\r\nIPP:   ipp://0.0.0.0:8631/printers/";
            _effectiveUrlLabel.Dock = DockStyle.Fill;
            _effectiveUrlLabel.ForeColor = System.Drawing.Color.DimGray;
            layout.SetColumnSpan(_effectiveUrlLabel, 2);
            layout.Controls.Add(_effectiveUrlLabel, 1, 3);

            group.Controls.Add(layout);
            return group;
        }

        private Control CreateSharingGroup()
        {
            var group = new GroupBox
            {
                Text = "共享打印机",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 2,
                RowCount = 1,
                Padding = new Padding(10)
            };
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 42));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 58));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

            layout.Controls.Add(CreateInstalledPrintersPanel(), 0, 0);
            layout.Controls.Add(CreateSharedPrintersPanel(), 1, 0);

            group.Controls.Add(layout);
            return group;
        }

        private Control CreateInstalledPrintersPanel()
        {
            var panel = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 3
            };
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 36));
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));

            var header = new TableLayoutPanel
            {
                ColumnCount = 2,
                Dock = DockStyle.Fill
            };
            header.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            header.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));

            var installedLabel = new Label
            {
                Text = "已安装打印机",
                AutoSize = true,
                Anchor = AnchorStyles.Left,
                TextAlign = System.Drawing.ContentAlignment.MiddleLeft
            };
            header.Controls.Add(installedLabel, 0, 0);

            _refreshPrintersButton.Text = "刷新列表";
            _refreshPrintersButton.AutoSize = false;
            _refreshPrintersButton.Width = 90;
            _refreshPrintersButton.Height = 28;
            _refreshPrintersButton.Margin = new Padding(0, 2, 0, 0);
            _refreshPrintersButton.Anchor = AnchorStyles.Right;
            header.Controls.Add(_refreshPrintersButton, 1, 0);

            panel.Controls.Add(header, 0, 0);

            _installedPrintersListBox.Dock = DockStyle.Fill;
            _installedPrintersListBox.BorderStyle = BorderStyle.FixedSingle;
            panel.Controls.Add(_installedPrintersListBox, 0, 1);

            var queueRow = new TableLayoutPanel
            {
                ColumnCount = 3,
                Dock = DockStyle.Fill,
                Padding = new Padding(0, 5, 0, 0)
            };
            queueRow.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            queueRow.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            queueRow.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));

            var queueLabel = new Label
            {
                Text = "队列名称：",
                AutoSize = true,
                Anchor = AnchorStyles.Left
            };
            queueRow.Controls.Add(queueLabel, 0, 0);

            _queueNameTextBox.Dock = DockStyle.Fill;
            queueRow.Controls.Add(_queueNameTextBox, 1, 0);

            _addMappingButton.Text = "添加共享";
            _addMappingButton.AutoSize = false;
            _addMappingButton.Width = 110;
            _addMappingButton.Height = 28;
            _addMappingButton.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            _addMappingButton.Margin = new Padding(10, 0, 0, 0);
            queueRow.Controls.Add(_addMappingButton, 2, 0);

            panel.Controls.Add(queueRow, 0, 2);

            return panel;
        }

        private Control CreateSharedPrintersPanel()
        {
            var panel = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2
            };
            panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30));
            panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

            var top = new TableLayoutPanel
            {
                ColumnCount = 2,
                Dock = DockStyle.Fill
            };
            top.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            top.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 110));

            var sharedLabel = new Label
            {
                Text = "已共享的打印机",
                AutoSize = true,
                TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
                Anchor = AnchorStyles.Left
            };
            top.Controls.Add(sharedLabel, 0, 0);

            _removeMappingButton.Text = "删除选中";
            _removeMappingButton.AutoSize = false;
            _removeMappingButton.Dock = DockStyle.Fill;
            _removeMappingButton.Height = 28;
            top.Controls.Add(_removeMappingButton, 1, 0);
            panel.Controls.Add(top, 0, 0);

            _mappingGrid.Dock = DockStyle.Fill;
            _mappingGrid.AutoGenerateColumns = false;
            _mappingGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            _mappingGrid.MultiSelect = false;
            _mappingGrid.AllowUserToAddRows = false;
            _mappingGrid.EditMode = DataGridViewEditMode.EditOnEnter;
            _mappingGrid.ReadOnly = false;
            _mappingGrid.BorderStyle = BorderStyle.FixedSingle;
            if (_mappingGrid.Columns.Count == 0)
            {
                _mappingGrid.Columns.Add(new DataGridViewTextBoxColumn
                {
                    HeaderText = "队列名称",
                    DataPropertyName = nameof(PrinterMapping.QueueName),
                    AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
                });
                _printerComboColumn = new DataGridViewComboBoxColumn
                {
                    HeaderText = "目标打印机",
                    DataPropertyName = nameof(PrinterMapping.PrinterName),
                    AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
                    DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton,
                    FlatStyle = FlatStyle.Standard,
                    DataSource = _installedPrinters
                };
                _mappingGrid.Columns.Add(_printerComboColumn);
            }
            panel.Controls.Add(_mappingGrid, 0, 1);

            return panel;
        }

        private Control CreateActionsPanel()
        {
            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 2,
                Padding = new Padding(0, 8, 0, 0)
            };
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50));

            var optionsPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight,
                AutoSize = true,
                WrapContents = true
            };

            _autoStartCheckBox.Text = "启动后自动开启服务";
            _autoStartCheckBox.AutoSize = true;
            optionsPanel.Controls.Add(_autoStartCheckBox);

            _runOnBootCheckBox.Text = "开启自启动";
            _runOnBootCheckBox.AutoSize = true;
            optionsPanel.Controls.Add(_runOnBootCheckBox);

            _enableMdnsCheckBox.Text = "开启mDNS发现服务";
            _enableMdnsCheckBox.AutoSize = true;
            optionsPanel.Controls.Add(_enableMdnsCheckBox);

            var buttonsPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.RightToLeft,
                WrapContents = true
            };

            _startButton.Text = "启动服务";
            _stopButton.Text = "停止服务";
            _stopButton.Enabled = false;
            _saveButton.Text = "保存配置";
            _installServiceButton.Text = "设置管理员密码";

            buttonsPanel.Controls.Add(_installServiceButton);
            buttonsPanel.Controls.Add(_saveButton);
            buttonsPanel.Controls.Add(_stopButton);
            buttonsPanel.Controls.Add(_startButton);

            layout.Controls.Add(optionsPanel, 0, 0);
            layout.Controls.Add(buttonsPanel, 1, 0);

            return layout;
        }

        private Control CreateSharedStatusPanel()
        {
            var panel = new Panel
            {
                Dock = DockStyle.Fill,
                // 紧凑的上下内边距，让状态栏高度更贴合文字
                Padding = new Padding(12, 4, 12, 4),
                BackColor = Color.FromArgb(245, 245, 245)
            };

            // 使用水平布局：前缀 + IPP 状态 + TCP 状态，分别可以设置颜色
            var layout = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight,
                WrapContents = false,
                AutoSize = false,
                Padding = new Padding(0, 0, 0, 0)
            };

            _sharedStatusLabel.AutoSize = true;
            _sharedStatusLabel.TextAlign = ContentAlignment.MiddleLeft;
            _sharedStatusLabel.Font = new Font(Font, FontStyle.Bold);
            _sharedStatusLabel.Text = "服务状态：";
            layout.Controls.Add(_sharedStatusLabel);

            _statusLabel.AutoSize = false;
            _statusLabel.AutoSize = true;
            _statusLabel.Margin = new Padding(8, 0, 0, 0);
            _statusLabel.Text = "IPP 服务：未就绪";
            _statusLabel.ForeColor = Color.Gray;
            layout.Controls.Add(_statusLabel);

            // 两个服务状态之间的竖线分隔符
            var separatorLabel = new Label
            {
                AutoSize = true,
                Text = "|",
                ForeColor = Color.Gray,
                Margin = new Padding(8, 0, 8, 0)
            };
            layout.Controls.Add(separatorLabel);

            _tcpStatusLabel.AutoSize = false;
            _tcpStatusLabel.AutoSize = true;
            _tcpStatusLabel.Margin = new Padding(0, 0, 0, 0);
            _tcpStatusLabel.Text = "TCP 9100 服务：离线";
            _tcpStatusLabel.ForeColor = Color.Gray;

            layout.Controls.Add(_tcpStatusLabel);

            panel.Controls.Add(layout);

            UpdateSharedStatusLabelText();

            return panel;
        }

        private void InitializeLogTab()
        {
            var logLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                ColumnCount = 1,
                Padding = new Padding(5)
            };
            logLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            logLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));

            _logTextBox.Dock = DockStyle.Fill;
            _logTextBox.ReadOnly = true;
            _logTextBox.BackColor = System.Drawing.Color.Black;
            _logTextBox.ForeColor = System.Drawing.Color.LightGreen;
            _logTextBox.Font = new System.Drawing.Font("Consolas", 9);
            _logTextBox.BorderStyle = BorderStyle.FixedSingle;

            logLayout.Controls.Add(_logTextBox, 0, 0);

            var footer = new FlowLayoutPanel
            {
                FlowDirection = FlowDirection.LeftToRight,
                Dock = DockStyle.Fill
            };
            _clearLogButton.Text = "清空日志";
            footer.Controls.Add(_clearLogButton);
            logLayout.Controls.Add(footer, 0, 1);

            _logTab.Controls.Add(logLayout);
            _tabControl.TabPages.Add(_logTab);
        }

        private void InitializeAboutTab()
        {
            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 1,
                RowCount = 4,
                Padding = new Padding(20),
                BackColor = Color.White
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 120));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 60));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 55));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 45));

            var logoPanel = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 1,
                RowCount = 1
            };
            var logoPicture = new PictureBox
            {
                Width = 120,
                Height = 120,
                SizeMode = PictureBoxSizeMode.Zoom, // 保持原图比例缩放
                Anchor = AnchorStyles.None,
                Margin = new Padding(0)
            };
            logoPicture.Image = LoadAboutLogoImage();
            logoPanel.Controls.Add(logoPicture, 0, 0);
            layout.Controls.Add(logoPanel, 0, 0);

            var titlePanel = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 1,
                RowCount = 2
            };
            titlePanel.RowStyles.Add(new RowStyle(SizeType.Percent, 60));
            titlePanel.RowStyles.Add(new RowStyle(SizeType.Percent, 40));

            var titleLabel = new Label
            {
                Text = "IPP Server 管理控制台",
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.BottomCenter,
                Font = new Font(Font.FontFamily, 14, FontStyle.Bold)
            };
            titlePanel.Controls.Add(titleLabel, 0, 0);

            var versionLabel = new Label
            {
                Text = $"版本：{GetVersionDisplayText()}",
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.TopCenter,
                ForeColor = Color.DimGray
            };
            titlePanel.Controls.Add(versionLabel, 0, 1);
            layout.Controls.Add(titlePanel, 0, 1);

            var featureGroup = new GroupBox
            {
                Text = "核心功能",
                Dock = DockStyle.Fill
            };
            var featureLabel = new Label
            {
                Dock = DockStyle.Fill,
                TextAlign = ContentAlignment.TopLeft,
                Padding = new Padding(8, 4, 8, 4),
                AutoSize = false,
                Text = "- 支持 IPP 与 TCP9100 网络打印服务并行运行。\r\n" +
                       "- GUI / WebUI 双向实时同步配置。\r\n" +
                       "- IP/MAC 访问限制与日志追踪。\r\n" +
                       "- Web 管理平台可进行简单认证与密码管理。\r\n" +
                       "- 便捷导出日志与网络服务控制。"
            };
            featureGroup.Controls.Add(featureLabel);
            layout.Controls.Add(featureGroup, 0, 2);

            var infoGroup = new GroupBox
            {
                Text = "关于我们",
                Dock = DockStyle.Fill
            };
            var infoLayout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 2,
                RowCount = 5,
                Padding = new Padding(10, 6, 10, 6)
            };
            infoLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 90));
            infoLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            infoLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 24));
            infoLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 24));
            infoLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 24));
            infoLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 24));
            infoLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));

            void AddInfoRow(string label, string value, int row)
            {
                infoLayout.Controls.Add(new Label
                {
                    Text = label,
                    TextAlign = ContentAlignment.MiddleRight,
                    Dock = DockStyle.Fill,
                    ForeColor = Color.DimGray
                }, 0, row);
                infoLayout.Controls.Add(new Label
                {
                    Text = value,
                    TextAlign = ContentAlignment.MiddleLeft,
                    Dock = DockStyle.Fill
                }, 1, row);
            }

            AddInfoRow("作   者：", "草原企鹅", 0);
            AddInfoRow("联系方式：", "tyq@qq.com", 1);
            AddInfoRow("微信：", "15242609", 2);
            AddInfoRow("项目主页：", "https://github.com/btwise/ipp-server", 3);

            infoGroup.Controls.Add(infoLayout);
            layout.Controls.Add(infoGroup, 0, 3);

            _aboutTab.Padding = new Padding(3);
            _aboutTab.Controls.Add(layout);
            _tabControl.TabPages.Add(_aboutTab);
        }

        private Image LoadAboutLogoImage()
        {
            try
            {
                var assembly = Assembly.GetExecutingAssembly();
                var resourceName = assembly.GetManifestResourceNames()
                    .FirstOrDefault(name => name.EndsWith(".myself.png", StringComparison.OrdinalIgnoreCase));
                if (!string.IsNullOrEmpty(resourceName))
                {
                    using var stream = assembly.GetManifestResourceStream(resourceName);
                    if (stream != null)
                    {
                        return Image.FromStream(stream);
                    }
                }
            }
            catch
            {
                // 忽略自定义 LOGO 加载异常
            }

            // 回退到应用图标
            return (_appIcon ?? Icon ?? SystemIcons.Application).ToBitmap();
        }

        private void InitializeTcpTab()
        {
            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                ColumnCount = 1,
                Padding = new Padding(8)
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 90));

            layout.Controls.Add(CreateTcpTaskPanel(), 0, 0);
            layout.Controls.Add(CreateTcpActionPanel(), 0, 1);

            _tcpTab.Padding = new Padding(3);
            _tcpTab.Controls.Add(layout);
            _tabControl.TabPages.Add(_tcpTab);
        }

        private Control CreateTcpTaskPanel()
        {
            var group = new GroupBox
            {
                Text = "TCP 打印任务",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                ColumnCount = 1
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));

            ConfigureTcpTaskGridColumns();
            _tcpTaskGrid.Dock = DockStyle.Fill;
            _tcpTaskGrid.AutoGenerateColumns = false;
            _tcpTaskGrid.DataSource = _tcpTasks;
            _tcpTaskGrid.AllowUserToAddRows = false;
            _tcpTaskGrid.AllowUserToDeleteRows = false;
            _tcpTaskGrid.RowHeadersVisible = false;
            _tcpTaskGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            _tcpTaskGrid.RowPostPaint += (_, e) =>
            {
                if (e.RowIndex >= 0 && e.RowIndex < _tcpTaskGrid.Rows.Count)
                {
                    _tcpTaskGrid.Rows[e.RowIndex].Cells[0].Value = (e.RowIndex + 1).ToString();
                }
            };

            layout.Controls.Add(_tcpTaskGrid, 0, 0);

            var buttonPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight
            };

            _tcpAddButton.Text = "添加";
            _tcpRemoveButton.Text = "删除";
            buttonPanel.Controls.Add(_tcpAddButton);
            buttonPanel.Controls.Add(_tcpRemoveButton);

            layout.Controls.Add(buttonPanel, 0, 1);

            group.Controls.Add(layout);
            return group;
        }

        private void ConfigureTcpTaskGridColumns()
        {
            if (_tcpTaskGrid.Columns.Count > 0)
            {
                return;
            }

            var indexColumn = new DataGridViewTextBoxColumn
            {
                HeaderText = "序号",
                Width = 60,
                ReadOnly = true,
                ValueType = typeof(string),
                SortMode = DataGridViewColumnSortMode.NotSortable
            };
            _tcpTaskGrid.Columns.Add(indexColumn);

            _tcpPrinterComboColumn = new DataGridViewComboBoxColumn
            {
                HeaderText = "打印机名称",
                DataPropertyName = nameof(TcpPrinterTask.PrinterName),
                DataSource = _installedPrinters,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
                DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton,
                FlatStyle = FlatStyle.Standard
            };
            _tcpTaskGrid.Columns.Add(_tcpPrinterComboColumn);

            var portColumn = new DataGridViewTextBoxColumn
            {
                HeaderText = "端口",
                DataPropertyName = nameof(TcpPrinterTask.Port),
                Width = 80
            };
            _tcpTaskGrid.Columns.Add(portColumn);

            _tcpModeComboColumn = new DataGridViewComboBoxColumn
            {
                HeaderText = "打印模式",
                DataPropertyName = nameof(TcpPrinterTask.PrintMode),
                DataSource = new[] { "自动", "RAW", "XPS" },
                Width = 120,
                DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton,
                FlatStyle = FlatStyle.Standard
            };
            _tcpTaskGrid.Columns.Add(_tcpModeComboColumn);
        }

        private Control CreateTcpActionPanel()
        {
            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 2
            };
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 60));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40));

            var optionPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.TopDown
            };

            _enableTcpServiceCheckBox.Text = "开启 TCP 9100 打印服务（随 IPP 服务启动）";
            _enableTcpServiceCheckBox.AutoSize = true;
            optionPanel.Controls.Add(_enableTcpServiceCheckBox);

            var buttonPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.RightToLeft
            };

            _tcpStartButton.Text = "启动 TCP 服务";
            _tcpStopButton.Text = "停止 TCP 服务";
            _tcpStopButton.Enabled = false;
            buttonPanel.Controls.Add(_tcpStopButton);
            buttonPanel.Controls.Add(_tcpStartButton);

            layout.Controls.Add(optionPanel, 0, 0);
            layout.Controls.Add(buttonPanel, 1, 0);

            return layout;
        }

        private void BindData()
        {
            ApplyPrefixToInputs(_settings.BasePrefix);
            _installedPrintersListBox.DataSource = _installedPrinters;
            _mappingGrid.DataSource = _printerMappings;
            _tcpTaskGrid.DataSource = _tcpTasks;
        }

        private void PersistNetworkSettingsIfReady()
        {
            if (_isUpdatingNetworkInputs)
            {
                return;
            }
            PersistSettingsSilently();
        }

        private void ApplyPrefixToInputs(string prefix)
        {
            _isUpdatingNetworkInputs = true;
            try
            {
                var hostValue = "+";
                var port = 8631;
                var path = "/printers/";

                if (!string.IsNullOrWhiteSpace(prefix))
                {
                    if (prefix.Contains("+:"))
                    {
                        hostValue = "+";
                        var sanitized = prefix.Replace("+", "127.0.0.1");
                        if (Uri.TryCreate(sanitized, UriKind.Absolute, out var uri))
                        {
                            port = uri.Port;
                            path = uri.AbsolutePath;
                        }
                    }
                    else if (Uri.TryCreate(prefix, UriKind.Absolute, out var uri))
                    {
                        hostValue = uri.Host;
                        port = uri.Port;
                        path = uri.AbsolutePath;
                    }
                }

                SelectInterface(hostValue);
                _portInput.Value = Math.Max(_portInput.Minimum, Math.Min(_portInput.Maximum, port));
                _pathTextBox.Text = NormalizePath(path);
            }
            finally
            {
                _isUpdatingNetworkInputs = false;
            }

            UpdateEffectiveUrlPreview();
        }

        private void SelectInterface(string hostValue)
        {
            if (string.IsNullOrWhiteSpace(hostValue))
            {
                hostValue = "+";
            }

            var option = _interfaceOptions.FirstOrDefault(o => string.Equals(o.Value, hostValue, StringComparison.OrdinalIgnoreCase));
            if (option == null)
            {
                option = new InterfaceOption(hostValue == "+" ? "所有网卡 (0.0.0.0)" : hostValue, hostValue);
                _interfaceOptions.Add(option);
            }

            _interfaceCombo.SelectedItem = option;
        }

        private void UpdateEffectiveUrlPreview()
        {
            if (_isUpdatingNetworkInputs)
            {
                return;
            }

            var hostValue = GetSelectedInterfaceValue();
            var port = (int)_portInput.Value;
            var path = NormalizePath(_pathTextBox.Text);
            var sampleHost = hostValue == "+" ? _interfaceOptions.FirstOrDefault(o => o.Value != "+" && o.Value != "127.0.0.1")?.Value ?? "示例IP" : hostValue;

            var httpPreview = hostValue == "+" ? $"http://0.0.0.0:{port}{path} (所有网卡)" : $"http://{hostValue}:{port}{path}";
            var ippPreview = $"ipp://{sampleHost}:{port}{path}";
            _effectiveUrlLabel.Text = $"HTTP: {httpPreview}{Environment.NewLine}IPP:   {ippPreview}";
        }

        private string BuildCurrentPrefix()
        {
            var hostValue = GetSelectedInterfaceValue();
            var port = (int)_portInput.Value;
            var path = NormalizePath(_pathTextBox.Text);
            var hostSegment = hostValue == "+" ? "+" : hostValue;
            return $"http://{hostSegment}:{port}{path}";
        }

        private string GetSelectedInterfaceValue()
        {
            return (_interfaceCombo.SelectedItem as InterfaceOption)?.Value ?? "+";
        }

        private bool ValidateListenerSettings()
        {
            var hostValue = GetSelectedInterfaceValue();
            var port = (int)_portInput.Value;

            if (!IsPortAvailable(hostValue, port))
            {
                MessageBox.Show($"端口 {port} 已被其他程序占用，请选择不同的端口。", "端口冲突", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        private void WireEvents()
        {
            _refreshPrintersButton.Click += (_, _) => LoadInstalledPrinters();
            _addMappingButton.Click += (_, _) => AddMapping(autoGenerateQueue: false, showNotification: false);
            _removeMappingButton.Click += (_, _) => RemoveMapping();
            _startButton.Click += (_, _) => StartIppServiceFromUi();
            _stopButton.Click += (_, _) => StopIppServiceFromUi();
            _saveButton.Click += (_, _) => SaveSettings();
            _installServiceButton.Click += (_, _) => SetAdminPassword();
            _installedPrintersListBox.SelectedIndexChanged += (_, _) => SuggestQueueNameFromSelection(force: true);
            _installedPrintersListBox.MouseDoubleClick += (_, _) =>
            {
                var hasCustomName = !string.IsNullOrWhiteSpace(_queueNameTextBox.Text);
                AddMapping(autoGenerateQueue: !hasCustomName, showNotification: true);
            };
            _clearLogButton.Click += (_, _) => ClearLog();
            _queueNameTextBox.TextChanged += (_, _) =>
            {
                if (_suppressQueueSuggestion)
                {
                    return;
                }
                _queueNameDirty = !string.IsNullOrWhiteSpace(_queueNameTextBox.Text);
            };
            _interfaceCombo.SelectedIndexChanged += (_, _) =>
            {
                UpdateEffectiveUrlPreview();
                PersistNetworkSettingsIfReady();
            };
            _refreshInterfacesButton.Click += (_, _) => LoadNetworkInterfaceOptions();
            _portInput.ValueChanged += (_, _) =>
            {
                UpdateEffectiveUrlPreview();
                PersistNetworkSettingsIfReady();
            };
            _pathTextBox.TextChanged += (_, _) =>
            {
                UpdateEffectiveUrlPreview();
                PersistNetworkSettingsIfReady();
            };
            _autoStartCheckBox.CheckedChanged += (_, _) => HandleAutoStartCheckChanged();
            _runOnBootCheckBox.CheckedChanged += (_, _) => HandleRunOnBootCheckChanged();
            _enableMdnsCheckBox.CheckedChanged += (_, _) => HandleEnableMdnsCheckChanged();
            _tcpAddButton.Click += (_, _) => AddTcpTask();
            _tcpRemoveButton.Click += (_, _) => RemoveTcpTask();
            _tcpStartButton.Click += (_, _) => StartTcpServiceFromUi();
            _tcpStopButton.Click += (_, _) => StopTcpServiceFromUi();
            _enableTcpServiceCheckBox.CheckedChanged += (_, _) => HandleTcpServiceToggleChanged();
            _tcpTaskGrid.DataError += (_, args) => args.ThrowException = false;
            _tcpTaskGrid.CurrentCellDirtyStateChanged += (_, _) =>
            {
                if (_tcpTaskGrid.IsCurrentCellDirty)
                {
                    _tcpTaskGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
                }
            };
            _tcpTaskGrid.CellValueChanged += (_, e) => HandleTcpTaskCellValueChanged(e);
            _tcpTaskGrid.CellBeginEdit += (_, e) => HandleTcpTaskCellBeginEdit(e);
            _mappingGrid.CurrentCellDirtyStateChanged += (_, _) =>
            {
                if (_mappingGrid.IsCurrentCellDirty)
                {
                    _mappingGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);
                }
            };
            _mappingGrid.CellValueChanged += (_, _) => PersistSettingsSilently();
        }

        private void InitializeOptionStates()
        {
            _initializingOptions = true;
            _autoStartCheckBox.Checked = _settings.AutoStart;
            _runOnBootCheckBox.Checked = _settings.RunOnBoot;
            _enableMdnsCheckBox.Checked = _settings.EnableMdnsDiscovery;
            _enableTcpServiceCheckBox.Checked = _settings.EnableTcp9100Service;
            
            // 初始化IP/MAC限制配置
            if (_settings.IpMacRestriction == null)
            {
                _settings.IpMacRestriction = Configuration.IpMacRestriction.CreateDefault();
            }
            var restriction = _settings.IpMacRestriction;
            
            // 确保列表不为null
            if (restriction.IpRules == null)
            {
                restriction.IpRules = new List<string>();
            }
            if (restriction.MacRules == null)
            {
                restriction.MacRules = new List<string>();
            }
            
            // 先加载列表数据，再设置控件值（避免触发事件时列表为空）
            _ipRulesList.Clear();
            foreach (var rule in restriction.IpRules)
            {
                if (!string.IsNullOrWhiteSpace(rule))
                {
                    _ipRulesList.Add(rule);
                }
            }
            
            _macRulesList.Clear();
            foreach (var rule in restriction.MacRules)
            {
                if (!string.IsNullOrWhiteSpace(rule))
                {
                    _macRulesList.Add(rule);
                }
            }
            
            // 最后设置控件值，此时列表已加载完成
            _enableRestrictionCheckBox.Checked = restriction.Enabled;
            _whitelistRadioButton.Checked = restriction.WhitelistMode;
            _blacklistRadioButton.Checked = !restriction.WhitelistMode;
            
            UpdateRestrictionControlsState();
            
            _initializingOptions = false;
            UpdateAutoRunRegistration(_settings.RunOnBoot);
            UpdateTcpServiceStatus();
        }

        private void TryAutoStartServiceOnLaunch()
        {
            if (!EnsureHostStarted())
            {
                return;
            }

            if (_settings.AutoStart)
            {
                if (HasValidPrinterMappings(out var error))
                {
                    var result = _host.StartIppService();
                    AppendLog(result.Message);
                    var prefix = _host.DisplayBasePrefix ?? _settings.BasePrefix;
                    UpdateStatus(true, prefix);
                    StartTcpServiceIfEnabled();
                }
                else
                {
                    AppendLog($"自动启动已跳过：{error}");
                }
            }
        }

        private void LoadNetworkInterfaceOptions()
        {
            var selectedValue = GetSelectedInterfaceValue();
            _isUpdatingNetworkInputs = true;
            try
            {
                _interfaceOptions.Clear();
                _interfaceOptions.Add(new InterfaceOption("所有网卡 (0.0.0.0)", "+"));

                foreach (var ip in GetLocalIpAddresses().Distinct().OrderBy(ip => ip))
                {
                    if (_interfaceOptions.All(opt => !string.Equals(opt.Value, ip, StringComparison.OrdinalIgnoreCase)))
                    {
                        _interfaceOptions.Add(new InterfaceOption(ip, ip));
                    }
                }

                _interfaceCombo.DataSource = null;
                _interfaceCombo.DataSource = _interfaceOptions;
                _interfaceCombo.DisplayMember = nameof(InterfaceOption.Display);

                if (!string.IsNullOrWhiteSpace(selectedValue))
                {
                    SelectInterface(selectedValue);
                }
                else
                {
                    SelectInterface("+");
                }
            }
            finally
            {
                _isUpdatingNetworkInputs = false;
            }

            UpdateEffectiveUrlPreview();
        }

        private void RefreshPrinterColumnDataSource()
        {
            if (_printerComboColumn != null)
            {
                _printerComboColumn.DataSource = null;
                _printerComboColumn.DataSource = _installedPrinters;
            }

            if (_tcpPrinterComboColumn != null)
            {
                _tcpPrinterComboColumn.DataSource = null;
                _tcpPrinterComboColumn.DataSource = _installedPrinters;
            }
        }

        private void LoadInstalledPrinters()
        {
            var printers = GetFilteredPrinterNames();
            _installedPrinters.Clear();
            foreach (var printer in printers)
            {
                _installedPrinters.Add(printer);
            }
            RefreshPrinterColumnDataSource();

            if (_installedPrinters.Count > 0)
            {
                _installedPrintersListBox.SelectedIndex = 0;
                SuggestQueueNameFromSelection(force: true);
            }
            else
            {
                SetQueueNameText(string.Empty, resetDirty: true);
            }
        }

        private bool AddMapping(bool autoGenerateQueue, bool showNotification)
        {
            var queueName = _queueNameTextBox.Text.Trim();
            var printerName = _installedPrintersListBox.SelectedItem as string;

            if (string.IsNullOrWhiteSpace(printerName))
            {
                MessageBox.Show("请选择一个本地打印机。");
                return false;
            }

            if (autoGenerateQueue || string.IsNullOrWhiteSpace(queueName))
            {
                queueName = GenerateQueueName(printerName);
                SetQueueNameText(queueName, resetDirty: true, selectAll: false);
            }

            if (_printerMappings.Any(m => string.Equals(m.QueueName, queueName, StringComparison.OrdinalIgnoreCase)))
            {
                MessageBox.Show("该队列名称已存在。");
                return false;
            }

            _printerMappings.Add(new PrinterMapping { QueueName = queueName, PrinterName = printerName });
            if (showNotification)
            {
                MessageBox.Show($"已将打印机 \"{printerName}\" 共享为队列 \"{queueName}\"。", "共享成功",
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            SetQueueNameText(string.Empty, resetDirty: true);
            return true;
        }

        private void RemoveMapping()
        {
            if (_mappingGrid.CurrentRow?.DataBoundItem is PrinterMapping mapping)
            {
                _printerMappings.Remove(mapping);
            }
        }

        private void AddTcpTask()
        {
            var port = 9100;
            var existingPorts = new HashSet<int>(_tcpTasks.Select(t => t.Port));
            while (existingPorts.Contains(port))
            {
                port++;
            }

            _tcpTasks.Add(new TcpPrinterTask
            {
                PrinterName = string.Empty,
                Port = port,
                PrintMode = "自动"
            });
            
            // 更新TCP防火墙规则
            UpdateTcpFirewallRules();
        }

        private void RemoveTcpTask()
        {
            if (_tcpTaskGrid.CurrentRow?.DataBoundItem is TcpPrinterTask task)
            {
                _tcpTasks.Remove(task);
                // 更新TCP防火墙规则
                UpdateTcpFirewallRules();
            }
        }

        private void HandleTcpServiceToggleChanged()
        {
            if (_initializingOptions || _settings == null)
            {
                return;
            }

            _settings.EnableTcp9100Service = _enableTcpServiceCheckBox.Checked;
            PersistSettingsSilently();

            if (!_enableTcpServiceCheckBox.Checked)
            {
                StopTcpServiceIfRunning();
            }
        }

        private void StartTcpServiceFromUi()
        {
            StartTcpService(interactive: true);
        }

        private void StopTcpServiceFromUi()
        {
            StopTcpService(interactive: true);
        }

        private void StartTcpService(bool interactive)
        {
            _tcpTaskGrid.EndEdit();

            if (_tcpServer == null)
            {
                _tcpServer = new Tcp9100PrintServer(AppendLog);
            }

            if (_tcpServer.IsRunning)
            {
                if (interactive)
                {
                    AppendLog("TCP 9100 服务已经在运行。");
                }
                UpdateTcpServiceStatus();
                return;
            }

            if (!HasValidTcpTasks(out var error))
            {
                AppendLog($"TCP 9100 服务无法启动：{error}");
                if (interactive)
                {
                    MessageBox.Show(error, "TCP 9100 服务", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
                return;
            }

            try
            {
                // 启动服务前，确保防火墙规则已更新
                UpdateTcpFirewallRules();
                
                _tcpServer.Start(_tcpTasks);
                PersistSettingsSilently();
                UpdateTcpServiceStatus();
            }
            catch (Exception ex)
            {
                AppendLog($"启动 TCP 9100 服务失败：{ex.Message}");
                if (interactive)
                {
                    MessageBox.Show($"启动 TCP 服务失败：{ex.Message}", "TCP 9100 服务", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void StopTcpService(bool interactive)
        {
            if (_tcpServer == null || !_tcpServer.IsRunning)
            {
                if (interactive)
                {
                    AppendLog("TCP 9100 服务未运行。");
                }
                UpdateTcpServiceStatus();
                return;
            }

            try
            {
                _tcpServer.StopAsync().GetAwaiter().GetResult();
                UpdateTcpServiceStatus();
            }
            catch (Exception ex)
            {
                AppendLog($"停止 TCP 9100 服务失败：{ex.Message}");
                if (interactive)
                {
                    MessageBox.Show($"停止 TCP 服务失败：{ex.Message}", "TCP 9100 服务", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void StartTcpServiceIfEnabled()
        {
            if (_enableTcpServiceCheckBox.Checked)
            {
                StartTcpService(interactive: false);
            }
        }

        private void StopTcpServiceIfRunning()
        {
            if (_tcpServer?.IsRunning == true)
            {
                StopTcpService(interactive: false);
            }
        }

        private bool HasValidTcpTasks(out string error)
        {
            if (_tcpTasks == null || _tcpTasks.Count == 0)
            {
                error = "请在 TCP 端口服务中至少添加一个打印任务。";
                return false;
            }

            foreach (var task in _tcpTasks)
            {
                if (task == null)
                {
                    error = "TCP 打印任务列表包含无效记录，请删除后重新添加。";
                    return false;
                }

                if (string.IsNullOrWhiteSpace(task.PrinterName))
                {
                    error = "TCP 打印任务中存在未指定打印机的记录。";
                    return false;
                }
                if (task.Port < 1 || task.Port > 65535)
                {
                    error = $"端口 {task.Port} 超出范围（1-65535）。";
                    return false;
                }
            }

            if (_tcpTasks.GroupBy(t => t.Port).Any(g => g.Count() > 1))
            {
                error = "TCP 打印任务中存在重复端口，请确保每个端口唯一。";
                return false;
            }

            error = null;
            return true;
        }

        private void UpdateTcpServiceStatus()
        {
            var running = _tcpServer?.IsRunning ?? false;
            // 企业级运维风格文案：在线 / 离线
            _tcpStatusLabel.Text = running ? "TCP 9100 服务：在线" : "TCP 9100 服务：离线";
            _tcpStatusLabel.ForeColor = running ? Color.ForestGreen : Color.DarkGray;
            _tcpStartButton.Enabled = !running;
            _tcpStopButton.Enabled = running;
            _tcpTaskGrid.Enabled = !running;
            _tcpAddButton.Enabled = !running;
            _tcpRemoveButton.Enabled = !running;
            UpdateSharedStatusLabelText();
        }

        private void UpdateSharedStatusLabelText()
        {
            // 目前仅作为前缀标签，颜色在单独的状态标签上体现
            _sharedStatusLabel.Text = "服务状态：";
        }

        private void HandleTcpTaskCellBeginEdit(DataGridViewCellCancelEventArgs e)
        {
            if (_tcpPrinterComboColumn == null || e.RowIndex < 0 || e.ColumnIndex != _tcpPrinterComboColumn.Index)
            {
                return;
            }

            var task = _tcpTaskGrid.Rows[e.RowIndex].DataBoundItem as TcpPrinterTask;
            _lastTcpPrinterSelection = task?.PrinterName ?? string.Empty;
        }

        private void HandleTcpTaskCellValueChanged(DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0)
            {
                return;
            }

            if (!(_tcpTaskGrid.Rows[e.RowIndex].DataBoundItem is TcpPrinterTask task))
            {
                return;
            }

            // 检查是否是打印机名称列
            if (_tcpPrinterComboColumn != null && e.ColumnIndex == _tcpPrinterComboColumn.Index)
            {
            var newPrinter = task.PrinterName;
            if (string.IsNullOrWhiteSpace(newPrinter))
            {
                return;
            }

            if (!ConfirmHostBasedPrinter(newPrinter))
            {
                task.PrinterName = _lastTcpPrinterSelection;
                _tcpTaskGrid.Refresh();
            }
            else
            {
                _lastTcpPrinterSelection = newPrinter;
                    PersistSettingsSilently();
                    // 更新TCP防火墙规则（端口可能未变，但打印机变化可能影响有效任务）
                    UpdateTcpFirewallRules();
                }
            }
            // 检查是否是端口列（列索引为2，端口列）
            else if (e.ColumnIndex == 2)
            {
                // 端口变化，更新防火墙规则
                PersistSettingsSilently();
                UpdateTcpFirewallRules();
            }
            // 检查是否是打印模式列（列索引为3）
            else if (e.ColumnIndex == 3)
            {
                // 打印模式变化，不需要更新防火墙
                PersistSettingsSilently();
            }
        }

        private bool ConfirmHostBasedPrinter(string printerName)
        {
            if (string.IsNullOrWhiteSpace(printerName))
            {
                return true;
            }

            if (_hostPrinterDetector.ShouldWarn(printerName, out var warningMessage))
            {
                var result = MessageBox.Show(
                    warningMessage + "\r\n\r\n此类打印机通常在每次打印前需要固件初始化，使用 TCP 9100 服务可能导致客户端任务无法结束或重复提交。\r\n\r\n是否仍然继续？",
                    "检测到可能的 GDI 打印机",
                    MessageBoxButtons.YesNo,
                    MessageBoxIcon.Warning);

                if (result != DialogResult.Yes)
                {
                    AppendLog($"用户取消使用可能的 GDI 打印机: {printerName}");
                    return false;
                }

                _hostPrinterDetector.MarkAcknowledged(printerName);
                AppendLog($"用户确认继续使用可能的 GDI 打印机: {printerName}");
            }

            return true;
        }

        private void SaveSettings(bool showMessage = true)
        {
            // 管理防火墙规则：如果端口改变，删除旧规则，添加新规则
            var currentPort = (int)_portInput.Value;
            var oldPort = _settings.LastUsedPort;
            
            PersistSettingsSilently(force: true);
            
            // 切换防火墙规则（如果端口改变）
            EnsureFirewallRuleForPort(currentPort, oldPort);
            
            if (showMessage)
            {
                MessageBox.Show("配置已保存。");
                AppendLog("配置已保存。");
            }
        }

        private void SuggestQueueNameFromSelection(bool force = false)
        {
            var printerName = _installedPrintersListBox.SelectedItem as string;
            if (string.IsNullOrWhiteSpace(printerName))
            {
                return;
            }

            if (!force && _queueNameDirty && !string.IsNullOrWhiteSpace(_queueNameTextBox.Text))
            {
                return;
            }

            var suggestion = GenerateQueueName(printerName);
            SetQueueNameText(suggestion, resetDirty: true, selectAll: true);
        }

        private void SetQueueNameText(string value, bool resetDirty = false, bool selectAll = false)
        {
            _suppressQueueSuggestion = true;
            _queueNameTextBox.Text = value;
            if (selectAll && !string.IsNullOrEmpty(value))
            {
                _queueNameTextBox.SelectionStart = 0;
                _queueNameTextBox.SelectionLength = value.Length;
            }
            _suppressQueueSuggestion = false;
            _queueNameDirty = !resetDirty && !string.IsNullOrWhiteSpace(value);
        }

        private string GenerateQueueName(string printerName)
        {
            if (string.IsNullOrWhiteSpace(printerName))
            {
                return "printer";
            }

            var builder = new StringBuilder();
            foreach (var ch in printerName.ToLowerInvariant())
            {
                if (char.IsLetterOrDigit(ch))
                {
                    builder.Append(ch);
                }
                else if (builder.Length > 0 && builder[builder.Length - 1] != '-')
                {
                    builder.Append('-');
                }
            }

            var baseName = builder.ToString().Trim('-');
            if (string.IsNullOrWhiteSpace(baseName))
            {
                baseName = "printer";
            }

            var candidate = baseName;
            var suffix = 1;
            while (_printerMappings.Any(m => string.Equals(m.QueueName, candidate, StringComparison.OrdinalIgnoreCase)))
            {
                candidate = $"{baseName}-{suffix++}";
            }

            return candidate;
        }

        private void UpdateServiceStatusLabel(bool hostRunning, bool ippRunning, string prefix = null)
        {
            if (!hostRunning)
            {
                // Web 宿主未就绪时，认为 IPP 服务整体“未就绪”
                _statusLabel.Text = "IPP 服务：未就绪";
                _statusLabel.ForeColor = Color.Gray;
                UpdateSharedStatusLabelText();
                return;
            }

            var displayPrefix = prefix ?? _host?.DisplayBasePrefix ?? _settings.BasePrefix;
            if (ippRunning)
            {
                // 宿主就绪且 IPP 服务开启：在线
                _statusLabel.Text = $"IPP 服务：在线 ({displayPrefix})";
                _statusLabel.ForeColor = Color.ForestGreen;
            }
            else
            {
                // 宿主已就绪但 IPP 未启用/已停止：离线
                _statusLabel.Text = $"IPP 服务：离线 ({displayPrefix})";
                _statusLabel.ForeColor = Color.DarkGray;
            }

            UpdateSharedStatusLabelText();
        }

        private void StartIppServiceFromUi()
        {
            if (!EnsureHostStarted())
            {
                return;
            }

            if (!HasValidPrinterMappings(out var validationError))
            {
                MessageBox.Show(validationError);
                return;
            }

            var result = _host.StartIppService();
            AppendLog(result.Message);
            var prefix = _host?.DisplayBasePrefix ?? _settings.BasePrefix;
            UpdateStatus(true, prefix);
            StartTcpServiceIfEnabled();
        }

        private void StopIppServiceFromUi()
        {
            if (_host == null)
            {
                AppendLog("IPP 服务尚未启动。");
                return;
            }

            var result = _host.StopIppService();
            AppendLog(result.Message);
            var prefix = _host?.DisplayBasePrefix ?? _settings.BasePrefix;
            UpdateStatus(true, prefix);
            StopTcpServiceIfRunning();
        }

        private bool EnsureHostStarted()
        {
            if (_host != null)
            {
                return true;
            }

            try
            {
                SaveSettings(showMessage: false);
                var config = ServerConfig.FromUserInput(_settings.BasePrefix, _settings.PrinterMappings);
                _host = new IppServerHost(config, AppendLog, _settings.EnableMdnsDiscovery);
                _host.IppServiceStateChanged += OnIppServiceStateChanged;
                
                // 设置 TCP 服务回调
                _host.SetTcpServiceCallbacks(
                    () => _tcpServer?.IsRunning ?? false,
                    () => {
                        try
                        {
                            StartTcpService(interactive: false);
                            return (true, "TCP 服务已启动");
                        }
                        catch (Exception ex)
                        {
                            return (false, ex.Message);
                        }
                    },
                    () => {
                        try
                        {
                            StopTcpService(interactive: false);
                            return (true, "TCP 服务已停止");
                        }
                        catch (Exception ex)
                        {
                            return (false, ex.Message);
                        }
                    },
                    () => _tcpTasks?.ToList() ?? new List<TcpPrinterTask>(),
                    (task) => {
                        try
                        {
                            if (_tcpTasks == null) return (false, "TCP 任务列表未初始化");
                            _tcpTasks.Add(task);
                            PersistSettingsSilently();
                            // 更新TCP防火墙规则
                            UpdateTcpFirewallRules();
                            return (true, "TCP 任务已添加");
                        }
                        catch (Exception ex)
                        {
                            return (false, ex.Message);
                        }
                    },
                    (index) => {
                        try
                        {
                            if (_tcpTasks == null || index < 0 || index >= _tcpTasks.Count)
                                return (false, "无效的任务索引");
                            _tcpTasks.RemoveAt(index);
                            PersistSettingsSilently();
                            // 更新TCP防火墙规则
                            UpdateTcpFirewallRules();
                            return (true, "TCP 任务已删除");
                        }
                        catch (Exception ex)
                        {
                            return (false, ex.Message);
                        }
                    },
                    (index, task) => {
                        try
                        {
                            if (_tcpTasks == null || index < 0 || index >= _tcpTasks.Count)
                                return (false, "无效的任务索引");
                            _tcpTasks[index] = task;
                            PersistSettingsSilently();
                            // 更新TCP防火墙规则
                            UpdateTcpFirewallRules();
                            return (true, "TCP 任务已更新");
                        }
                        catch (Exception ex)
                        {
                            return (false, ex.Message);
                        }
                    });
                
                // 重新设置IPP服务回调，包装启动逻辑以支持TCP服务自动启动
                _host.AdminWebUI?.ConfigureServiceControlCallbacks(
                    () => _host?.IsIppServiceEnabled ?? false,
                    () => {
                        var result = _host.StartIppService();
                        if (result.Success)
                        {
                            // 检查设置并启动TCP服务
                            StartTcpServiceIfEnabled();
                        }
                        return result;
                    },
                    () => {
                        var result = _host.StopIppService();
                        if (result.Success)
                        {
                            // 停止TCP服务
                            StopTcpServiceIfRunning();
                        }
                        return result;
                    },
                    () => {
                        var stopResult = _host.StopIppService();
                        if (stopResult.Success)
                        {
                            StopTcpServiceIfRunning();
                            var startResult = _host.StartIppService();
                            if (startResult.Success)
                            {
                                StartTcpServiceIfEnabled();
                            }
                            return startResult;
                        }
                        return stopResult;
                    });
                
                // 设置 TCP 服务的作业记录回调
                if (_tcpServer != null && _host != null)
                {
                    _tcpServer.SetJobCallbacks(
                        (port, printerName, clientIp, printMode, dataSize) => _host.RecordTcpJob(port, printerName, clientIp, printMode, dataSize),
                        (jobId, state, errorMessage) => _host.UpdateTcpJobState(jobId, state, errorMessage));
                }
                
                _host.Start();
                var displayPrefix = _host.DisplayBasePrefix ?? config.BasePrefix;
                UpdateStatus(true, displayPrefix);
                AppendLog("Web 管理服务已启动。");
                return true;
            }
            catch (Exception ex)
            {
                AppendLog($"启动 Web 服务失败：{ex}");
                return false;
            }
        }

        private void StopServer()
        {
            if (_host != null)
            {
                _host.IppServiceStateChanged -= OnIppServiceStateChanged;
                _host.Dispose();
                _host = null;
            }
            StopTcpServiceIfRunning();
            UpdateStatus(false);
            AppendLog("服务已停止。");
        }

        private void UpdateStatus(bool hostRunning, string prefix = null)
        {
            var ippRunning = hostRunning && (_host?.IsIppServiceEnabled ?? false);
            var editingLocked = ippRunning;

            _startButton.Enabled = !ippRunning;
            _stopButton.Enabled = ippRunning;
            _interfaceCombo.Enabled = !editingLocked;
            _refreshInterfacesButton.Enabled = !editingLocked;
            _portInput.Enabled = !editingLocked;
            _pathTextBox.Enabled = !editingLocked;
            _installedPrintersListBox.Enabled = !editingLocked;
            _queueNameTextBox.Enabled = !editingLocked;
            _addMappingButton.Enabled = !editingLocked;
            _removeMappingButton.Enabled = !editingLocked;
            _mappingGrid.Enabled = !editingLocked;
            _refreshPrintersButton.Enabled = !editingLocked;

            UpdateServiceStatusLabel(hostRunning, ippRunning, prefix);
            UpdateTrayMenuState();
        }

        private void SetAdminPassword()
        {
            var settings = Configuration.AppSettingsStore.Load();
            var hasPassword = !string.IsNullOrEmpty(settings.AdminPasswordHash);
            
            using (var dialog = new Form
            {
                Text = hasPassword ? "修改WEB管理员密码" : "设置WEB管理员密码",
                Width = 450,
                Height = hasPassword ? 200 : 220,
                FormBorderStyle = FormBorderStyle.FixedDialog,
                MaximizeBox = false,
                MinimizeBox = false,
                StartPosition = FormStartPosition.CenterParent
            })
            {
                var layout = new TableLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    Padding = new System.Windows.Forms.Padding(20, 15, 20, 8),
                    ColumnCount = 1,
                    RowCount = hasPassword ? 5 : 6
                };
                
                // 设置行样式 - 紧凑布局
                if (!hasPassword)
                {
                    layout.RowStyles.Add(new RowStyle(SizeType.AutoSize)); // 提示信息
                }
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 20)); // 密码标签
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 25)); // 密码输入框
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 20)); // 确认密码标签
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 25)); // 确认密码输入框
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); // 按钮行固定高度（紧凑）
                
                int currentRow = 0;
                
                if (!hasPassword)
                {
                    var infoLabel = new Label
                    {
                        Text = "首次设置管理员密码后，Web管理界面将需要密码登录。\r\n请妥善保管密码。",
                        AutoSize = true,
                        ForeColor = System.Drawing.Color.DarkBlue,
                        Margin = new System.Windows.Forms.Padding(0, 0, 0, 6)
                    };
                    layout.Controls.Add(infoLabel, 0, currentRow++);
                }
                
                var passwordLabel = new Label
                {
                    Text = hasPassword ? "新密码：" : "管理员密码：",
                    AutoSize = false,
                    Dock = DockStyle.Fill,
                    TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
                    Margin = new System.Windows.Forms.Padding(0)
                };
                layout.Controls.Add(passwordLabel, 0, currentRow++);
                
                var passwordTextBox = new TextBox
                {
                    UseSystemPasswordChar = true,
                    Dock = DockStyle.Fill,
                    Margin = new System.Windows.Forms.Padding(0, 0, 0, 6)
                };
                layout.Controls.Add(passwordTextBox, 0, currentRow++);
                
                var confirmLabel = new Label
                {
                    Text = "确认密码：",
                    AutoSize = false,
                    Dock = DockStyle.Fill,
                    TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
                    Margin = new System.Windows.Forms.Padding(0)
                };
                layout.Controls.Add(confirmLabel, 0, currentRow++);
                
                var confirmTextBox = new TextBox
                {
                    UseSystemPasswordChar = true,
                    Dock = DockStyle.Fill,
                    Margin = new System.Windows.Forms.Padding(0, 0, 0, 8)
                };
                layout.Controls.Add(confirmTextBox, 0, currentRow++);
                
                var buttonPanel = new FlowLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    FlowDirection = FlowDirection.RightToLeft,
                    WrapContents = false,
                    Padding = new System.Windows.Forms.Padding(0, 3, 0, 0)
                };
                
                var okButton = new Button
                {
                    Text = "确定",
                    DialogResult = DialogResult.OK,
                    Width = 75,
                    Height = 23,
                    UseVisualStyleBackColor = true,
                    Margin = new System.Windows.Forms.Padding(0)
                };
                
                var cancelButton = new Button
                {
                    Text = "取消",
                    DialogResult = DialogResult.Cancel,
                    Width = 75,
                    Height = 23,
                    UseVisualStyleBackColor = true,
                    Margin = new System.Windows.Forms.Padding(8, 0, 0, 0)
                };
                
                buttonPanel.Controls.Add(okButton);
                buttonPanel.Controls.Add(cancelButton);
                layout.Controls.Add(buttonPanel, 0, currentRow);
                
                dialog.Controls.Add(layout);
                dialog.AcceptButton = okButton;
                dialog.CancelButton = cancelButton;
                
                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    var password = passwordTextBox.Text;
                    var confirm = confirmTextBox.Text;
                    
                    if (string.IsNullOrEmpty(password))
                    {
                        MessageBox.Show("密码不能为空。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }
                    
                    if (password.Length < 6)
                    {
                        MessageBox.Show("密码长度至少为6个字符。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }
                    
                    if (password != confirm)
                    {
                        MessageBox.Show("两次输入的密码不一致。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }
                    
                    // 设置密码
                    settings.AdminPasswordHash = WebUI.AuthManager.HashPassword(password);
                    Configuration.AppSettingsStore.Save(settings);
                    
                    // 如果之前有初始化令牌，删除它（密码已设置）
                    Configuration.AdminPasswordInitializer.RemoveInitToken();
                    
                    MessageBox.Show(
                        hasPassword ? "管理员密码已修改。" : "管理员密码已设置。Web管理界面使用此密码登录。",
                        "成功",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information);
                    
                    AppendLog(hasPassword ? "WEB管理员密码已修改。" : "WEB管理员密码已设置。");
                }
            }
        }

        private void OnIppServiceStateChanged(bool isRunning)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action<bool>(OnIppServiceStateChanged), isRunning);
                return;
            }

            var prefix = _host?.DisplayBasePrefix ?? _settings.BasePrefix;
            UpdateStatus(_host != null, prefix);
        }

        private bool _isLoggingToHost = false; // 防止循环调用的标志

        private void AppendLog(string message)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action<string>(AppendLog), message);
                return;
            }

            var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
            _logTextBox.AppendText(line + Environment.NewLine);
            _logTextBox.SelectionStart = _logTextBox.TextLength;
            _logTextBox.ScrollToCaret();
            
            // 同时将日志发送到 IppServerHost，以便 WebUI 可以显示
            // 使用标志防止循环调用（因为 _host.Log 会调用 _logCallback，而 _logCallback 就是 AppendLog）
            if (_host != null && !_isLoggingToHost)
            {
                try
                {
                    _isLoggingToHost = true;
                    _host.Log(message);
                }
                catch
                {
                    // 忽略错误，避免影响GUI日志显示
                }
                finally
                {
                    _isLoggingToHost = false;
                }
            }
        }

        private static List<string> BuildAccessibleUrls(string basePrefix)
        {
            var urls = new List<string>();
            try
            {
                var ips = GetLocalIpAddresses();
                var port = ExtractPortFromPrefix(basePrefix);
                var path = ExtractPathFromPrefix(basePrefix);

                if (ips.Count == 0)
                {
                    urls.Add(basePrefix);
                }
                else
                {
                    foreach (var ip in ips)
                    {
                        urls.Add($"http://{ip}:{port}{path}");
                        urls.Add($"ipp://{ip}:{port}{path}");
                    }
                }
            }
            catch
            {
                urls.Add(basePrefix);
            }

            return urls;
        }

        private static int ExtractPortFromPrefix(string prefix)
        {
            if (string.IsNullOrWhiteSpace(prefix))
            {
                return 8631;
            }

            try
            {
                // 优先使用正则表达式直接从字符串中提取端口号（更可靠，不受URI解析影响）
                // 支持格式：http://+:8631/printers/ 或 http://192.168.1.1:8631/printers/
                var match = System.Text.RegularExpressions.Regex.Match(prefix, @":(\d+)/");
                if (match.Success && int.TryParse(match.Groups[1].Value, out var parsedPort) && parsedPort > 0)
                {
                    return parsedPort;
                }
                
                // 如果正则表达式失败，尝试使用 Uri 解析
                var uri = new Uri(prefix);
                if (uri.Port > 0)
                {
                    return uri.Port;
                }
                
                // 尝试从原始字符串中再次提取
                match = System.Text.RegularExpressions.Regex.Match(prefix, @":(\d+)");
                if (match.Success && int.TryParse(match.Groups[1].Value, out parsedPort) && parsedPort > 0)
                {
                    return parsedPort;
                }
                
                return 8631; // 默认值
            }
            catch
            {
                // 如果所有解析都失败，使用正则表达式从字符串中提取
                try
                {
                    var match = System.Text.RegularExpressions.Regex.Match(prefix, @":(\d+)");
                    if (match.Success && int.TryParse(match.Groups[1].Value, out var parsedPort) && parsedPort > 0)
                    {
                        return parsedPort;
                    }
                }
                catch
                {
                    // 忽略
                }
                
                return 8631;
            }
        }

        private static string ExtractPathFromPrefix(string prefix)
        {
            if (string.IsNullOrEmpty(prefix))
            {
                return "/printers/";
            }
            
            try
            {
                // 先尝试使用 Uri 解析（适用于标准 URI）
                var uri = new Uri(prefix);
                var path = uri.AbsolutePath;
                // 确保路径以 / 开头和结尾
                if (!path.EndsWith("/", StringComparison.Ordinal))
                {
                    path += "/";
                }
                return path;
            }
            catch
            {
                // 如果 Uri 解析失败（例如包含 + 或 *），使用正则表达式或字符串操作提取路径
                // 格式：http://host:port/path/ 或 http://+:port/path/
                var match = System.Text.RegularExpressions.Regex.Match(prefix, @"https?://[^/]+(/.+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                if (match.Success)
                {
                    var path = match.Groups[1].Value;
                    // 确保路径以 / 开头和结尾
                    if (!path.StartsWith("/", StringComparison.Ordinal))
                    {
                        path = "/" + path;
                    }
                    if (!path.EndsWith("/", StringComparison.Ordinal))
                    {
                        path += "/";
                    }
                    return path;
                }
                
                // 如果都失败了，返回默认值
                return "/printers/";
            }
        }

        /// <summary>
        /// 规范化BasePrefix用于显示（将通配符替换为实际IP）
        /// </summary>
        private static string NormalizeBasePrefixForDisplay(string prefix)
        {
            if (string.IsNullOrWhiteSpace(prefix))
            {
                return prefix;
            }

            var containsWildcardPlus = prefix.Contains("://+");
            var containsWildcardStar = prefix.Contains("://*");
            var containsWildcardAny = prefix.Contains("://0.0.0.0");
            
            if (!containsWildcardPlus && !containsWildcardStar && !containsWildcardAny)
            {
                // 没有通配符，直接返回
                return prefix;
            }

            // 提取端口和路径
            var port = ExtractPortFromPrefix(prefix);
            var path = ExtractPathFromPrefix(prefix);
            
            // 获取本地IP地址
            var localIps = GetLocalIpAddresses();
            var preferred = localIps.FirstOrDefault(ip => !ip.StartsWith("169.254.", StringComparison.Ordinal));
            var host = preferred ?? localIps.FirstOrDefault() ?? "127.0.0.1";
            
            // 构建新的URI
            return $"http://{host}:{port}{path}";
        }

        private void SetPrinterMappingsList(BindingList<PrinterMapping> list)
        {
            if (_printerMappings != null)
            {
                _printerMappings.ListChanged -= PrinterMappings_ListChanged;
            }

            _printerMappings = list ?? new BindingList<PrinterMapping>();
            _printerMappings.ListChanged += PrinterMappings_ListChanged;
        }

        private void SetTcpTaskList(BindingList<TcpPrinterTask> list)
        {
            if (_tcpTasks != null)
            {
                _tcpTasks.ListChanged -= TcpTasks_ListChanged;
            }

            _tcpTasks = list ?? new BindingList<TcpPrinterTask>();
            _tcpTasks.ListChanged += TcpTasks_ListChanged;
        }

        private void ExecuteWithAutoSaveSuspended(Action action)
        {
            var previous = _suppressAutoSave;
            _suppressAutoSave = true;
            try
            {
                action();
            }
            finally
            {
                _suppressAutoSave = previous;
            }
        }

        private static List<string> GetLocalIpAddresses()
        {
            var ips = new List<string>();
            try
            {
                foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
                {
                    if (ni.OperationalStatus != OperationalStatus.Up)
                    {
                        continue;
                    }

                    if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback ||
                        ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel)
                    {
                        continue;
                    }

                    foreach (var unicast in ni.GetIPProperties().UnicastAddresses)
                    {
                        var address = unicast.Address;
                        if (address.AddressFamily != AddressFamily.InterNetwork)
                        {
                            continue;
                        }

                        if (IPAddress.IsLoopback(address))
                        {
                            continue;
                        }

                        var text = address.ToString();
                        if (text.StartsWith("169.254.", StringComparison.Ordinal))
                        {
                            continue;
                        }

                        ips.Add(text);
                    }
                }
            }
            catch
            {
                // ignored
            }

            if (ips.Count == 0)
            {
                try
                {
                    var hostEntry = Dns.GetHostEntry(Dns.GetHostName());
                    foreach (var ip in hostEntry.AddressList)
                    {
                        if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
                        {
                            ips.Add(ip.ToString());
                        }
                    }
                }
                catch
                {
                    // ignored
                }
            }

            if (ips.Count == 0)
            {
                ips.Add("127.0.0.1");
            }

            return ips.Distinct().ToList();
        }

        private List<string> GetFilteredPrinterNames()
        {
            try
            {
                return Printing.PrinterFilter.GetPhysicalPrinters();
            }
            catch (Exception ex)
            {
                AppendLog($"读取打印机信息失败，已显示全部打印机：{ex.Message}");
                // 回退到显示所有打印机
                var allPrinters = new List<string>();
                    foreach (string printer in PrinterSettings.InstalledPrinters)
                    {
                    allPrinters.Add(printer);
                }
                return allPrinters.OrderBy(n => n, StringComparer.CurrentCultureIgnoreCase).ToList();
        }
        }

        private static bool IsPortAvailable(string hostValue, int port)
        {
            try
            {
                var properties = IPGlobalProperties.GetIPGlobalProperties();
                var listeners = properties.GetActiveTcpListeners();
                foreach (var endpoint in listeners)
                {
                    if (endpoint.Port != port)
                    {
                        continue;
                    }

                    if (hostValue == "+" || IPAddress.Any.Equals(endpoint.Address) || endpoint.Address.Equals(IPAddress.IPv6Any))
                    {
                        return false;
                    }

                    if (string.Equals(endpoint.Address.ToString(), hostValue, StringComparison.OrdinalIgnoreCase))
                    {
                        return false;
                    }
                }
            }
            catch
            {
                return true;
            }

            return true;
        }

        private static string NormalizePath(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return "/printers/";
            }

            var path = input.Trim();
            if (!path.StartsWith("/"))
            {
                path = "/" + path;
            }
            if (!path.EndsWith("/"))
            {
                path += "/";
            }
            return path;
        }

        private sealed class InterfaceOption
        {
            public InterfaceOption(string display, string value)
            {
                Display = display;
                Value = value;
            }

            public string Display { get; }
            public string Value { get; }

            public override string ToString() => Display;
        }

        private sealed class HostBasedPrinterDetector
        {
            private static readonly string[] ModelKeywords =
            {
                "LASERJET 1000",
                "LASERJET 1005",
                "LASERJET 1006",
                "LASERJET 1007",
                "LASERJET 1008",
                "LASERJET 1010",
                "LASERJET 1012",
                "LASERJET 1015",
                "LASERJET 1018",
                "LASERJET 1020",
                "LASERJET 1022",
                "LASERJET P1005",
                "LASERJET P1006",
                "LASERJET P1007",
                "LASERJET P1008",
                "LASERJET P1505",
                "HP 1010",
                "HP 1012",
                "HP 1015",
                "HP 1018",
                "HP1018",
                "HP 1020",
                "HP1020"
            };

            private static readonly string[] DriverKeywords =
            {
                "HOST-BASED",
                "HOSTBASED",
                "GDI",
                "SIHP",
                "DOT4"
            };

            private readonly HashSet<string> _acknowledgedPrinters = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
            private readonly object _lock = new object();

            public bool ShouldWarn(string printerName, out string warningMessage)
            {
                warningMessage = string.Empty;
                if (string.IsNullOrWhiteSpace(printerName))
                {
                    return false;
                }

                lock (_lock)
                {
                    if (_acknowledgedPrinters.Contains(printerName))
                    {
                        return false;
                    }
                }

                var driverName = GetDriverName(printerName);
                var evidence = FindKeywordEvidence(printerName, driverName);
                if (string.IsNullOrEmpty(evidence))
                {
                    evidence = InspectDriverFiles(printerName);
                }

                if (!string.IsNullOrEmpty(evidence))
                {
                    warningMessage = $"打印机 \"{printerName}\" 可能为 GDI/Host-Based 打印机。\r\n线索：{evidence}";
                    return true;
                }

                return false;
            }

            public void MarkAcknowledged(string printerName)
            {
                if (string.IsNullOrWhiteSpace(printerName))
                {
                    return;
                }

                lock (_lock)
                {
                    _acknowledgedPrinters.Add(printerName);
                }
            }

            private string GetDriverName(string printerName)
            {
                try
                {
                    using var searcher = new ManagementObjectSearcher("SELECT Name, DriverName FROM Win32_Printer");
                    using var collection = searcher.Get();
                    foreach (ManagementObject printer in collection)
                    {
                        var name = printer["Name"]?.ToString();
                        if (string.Equals(name, printerName, StringComparison.OrdinalIgnoreCase))
                        {
                            return printer["DriverName"]?.ToString() ?? string.Empty;
                        }
                    }
                }
                catch
                {
                    // ignored
                }

                return string.Empty;
            }

            private static string FindKeywordEvidence(string printerName, string driverName)
            {
                var normalizedPrinter = (printerName ?? string.Empty).ToUpperInvariant();
                var normalizedDriver = (driverName ?? string.Empty).ToUpperInvariant();

                var modelMatch = ModelKeywords.FirstOrDefault(keyword => normalizedPrinter.Contains(keyword));
                if (!string.IsNullOrEmpty(modelMatch))
                {
                    return $"打印机名称包含 \"{modelMatch}\"";
                }

                var driverMatch = DriverKeywords.FirstOrDefault(keyword => normalizedDriver.Contains(keyword));
                if (!string.IsNullOrEmpty(driverMatch))
                {
                    return $"驱动名称包含 \"{driverMatch}\"";
                }

                return string.Empty;
            }

            private string InspectDriverFiles(string printerName)
            {
                IntPtr hPrinter = IntPtr.Zero;
                IntPtr buffer = IntPtr.Zero;

                try
                {
                    if (!OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
                    {
                        return string.Empty;
                    }

                    int needed = 0;
                    if (!GetPrinterDriver(hPrinter, null, 2, IntPtr.Zero, 0, ref needed))
                    {
                        var error = Marshal.GetLastWin32Error();
                        if (error != ErrorInsufficientBuffer || needed <= 0)
                        {
                            return string.Empty;
                        }
                    }

                    buffer = Marshal.AllocHGlobal(needed);
                    if (!GetPrinterDriver(hPrinter, null, 2, buffer, needed, ref needed))
                    {
                        return string.Empty;
                    }

                    var info = Marshal.PtrToStructure<DRIVER_INFO_2>(buffer);
                    var candidates = new[]
                    {
                        PtrToString(info.pName),
                        PtrToString(info.pDriverPath),
                        PtrToString(info.pDataFile),
                        PtrToString(info.pConfigFile)
                    };

                    foreach (var entry in candidates)
                    {
                        if (string.IsNullOrEmpty(entry))
                        {
                            continue;
                        }

                        var upper = entry.ToUpperInvariant();
                        var keyword = DriverKeywords.FirstOrDefault(k => upper.Contains(k));
                        if (!string.IsNullOrEmpty(keyword))
                        {
                            return $"驱动文件包含 \"{keyword}\": {entry}";
                        }

                        if (upper.Contains("SIHP") || upper.EndsWith(".FLB", StringComparison.OrdinalIgnoreCase) || upper.EndsWith(".FLS", StringComparison.OrdinalIgnoreCase))
                        {
                            return $"驱动文件疑似固件：{entry}";
                        }
                    }
                }
                catch
                {
                    return string.Empty;
                }
                finally
                {
                    if (buffer != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(buffer);
                    }
                    if (hPrinter != IntPtr.Zero)
                    {
                        ClosePrinter(hPrinter);
                    }
                }

                return string.Empty;
            }

            private static string PtrToString(IntPtr ptr)
            {
                return ptr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringUni(ptr);
            }

            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            private struct DRIVER_INFO_2
            {
                public int cVersion;
                public IntPtr pName;
                public IntPtr pEnvironment;
                public IntPtr pDriverPath;
                public IntPtr pDataFile;
                public IntPtr pConfigFile;
            }

            private const int ErrorInsufficientBuffer = 122;

            [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
            private static extern bool GetPrinterDriver(IntPtr hPrinter, string pEnvironment, int level, IntPtr pDriverInfo, int cbBuf, ref int pcbNeeded);

            [DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
            private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);

            [DllImport("winspool.drv", SetLastError = true)]
            private static extern bool ClosePrinter(IntPtr hPrinter);
        }

        private void ClearLog()
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action(ClearLog));
                return;
            }

            _logTextBox.Clear();
        }

        private void PrinterMappings_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (_suppressAutoSave || _settings == null)
            {
                return;
            }
            PersistSettingsSilently();
        }

        private void TcpTasks_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (_suppressAutoSave || _settings == null)
            {
                return;
            }
            PersistSettingsSilently();
            // TCP任务列表变化时，更新防火墙规则
            UpdateTcpFirewallRules();
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            // 如果IPP服务仍在运行，则不允许直接退出
            if (_host != null && (_host.IsIppServiceEnabled))
            {
                var result = MessageBox.Show(
                    "IPP 服务当前仍在运行。\r\n为了避免中断客户端打印，请先在界面中停止服务，然后再退出程序。",
                    "无法退出",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                e.Cancel = true;
                return;
            }

            StopServer();
            _trayIcon?.Dispose();
            base.OnFormClosing(e);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _configWatcher?.Dispose();
                _trayIcon?.Dispose();
                _appIcon?.Dispose();
                _tcpServer?.Dispose();
            }
            base.Dispose(disposing);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if (WindowState == FormWindowState.Minimized)
            {
                HideToTray();
            }
        }

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            if (_launchedFromAutorun || _settings.AutoStart)
            {
                HideToTray(silent: true);
            }
        }

        private void HandleAutoStartCheckChanged()
        {
            if (_initializingOptions || _settings == null)
            {
                return;
            }
            _settings.AutoStart = _autoStartCheckBox.Checked;
            PersistSettingsSilently();
        }

        private void HandleRunOnBootCheckChanged()
        {
            if (_initializingOptions || _settings == null)
            {
                return;
            }
            _settings.RunOnBoot = _runOnBootCheckBox.Checked;
            PersistSettingsSilently();
            UpdateAutoRunRegistration(_settings.RunOnBoot);
        }

        private void HandleEnableMdnsCheckChanged()
        {
            if (_initializingOptions || _settings == null)
            {
                return;
            }
            _settings.EnableMdnsDiscovery = _enableMdnsCheckBox.Checked;
            PersistSettingsSilently();
        }

        private void PersistSettingsSilently(bool force = false)
        {
            if ((!force && (_suppressAutoSave || _settings == null)) || _settings == null)
            {
                return;
            }

            _settings.BasePrefix = BuildCurrentPrefix();
            _settings.PrinterMappings = _printerMappings.ToList();
            _settings.EnableTcp9100Service = _enableTcpServiceCheckBox.Checked;
            _settings.TcpPrinterTasks = _tcpTasks.ToList();
            _settings.LastUsedPort = (int)_portInput.Value;
            
            // 保存IP/MAC限制配置
            if (_settings.IpMacRestriction == null)
            {
                _settings.IpMacRestriction = Configuration.IpMacRestriction.CreateDefault();
            }
            _settings.IpMacRestriction.Enabled = _enableRestrictionCheckBox.Checked;
            _settings.IpMacRestriction.WhitelistMode = _whitelistRadioButton.Checked;
            _settings.IpMacRestriction.IpRules = _ipRulesList.ToList();
            _settings.IpMacRestriction.MacRules = _macRulesList.ToList();
            
            AppSettingsStore.Save(_settings);

            // 如果宿主已创建，则在配置变更后通知宿主进行热更新，
            // 这样 Web 管理界面看到的共享队列与 GUI 始终保持一致。
            // ReloadConfig 只读取配置并更新 ServerConfig，不会再次写文件，避免循环。
            if (_host != null)
            {
                try
                {
                    _host.ReloadConfig();
                }
                catch (Exception ex)
                {
                    AppendLog($"通知服务重载配置失败：{ex.Message}");
                }
            }
        }

        private bool HasValidPrinterMappings(out string error)
        {
            if (_printerMappings.Count == 0)
            {
                error = "请至少添加一个共享打印机。";
                return false;
            }

            foreach (var mapping in _printerMappings)
            {
                if (string.IsNullOrWhiteSpace(mapping.QueueName) || string.IsNullOrWhiteSpace(mapping.PrinterName))
                {
                    error = "存在无效的共享打印机映射，队列名称和目标打印机不能为空。";
                    return false;
                }
            }

            error = null;
            return true;
        }

        private void InitializeTrayIcon()
        {
            _trayMenu = new ContextMenuStrip();
            var showItem = new ToolStripMenuItem("显示主界面", null, (_, _) => ShowMainWindow());
            _trayStartMenuItem = new ToolStripMenuItem("启动服务", null, (_, _) => StartIppServiceFromUi());
            _trayStopMenuItem = new ToolStripMenuItem("停止服务", null, (_, _) => StopIppServiceFromUi());
            var exitItem = new ToolStripMenuItem("退出", null, (_, _) => ExitApplication());

            _trayMenu.Items.Add(showItem);
            _trayMenu.Items.Add(new ToolStripSeparator());
            _trayMenu.Items.Add(_trayStartMenuItem);
            _trayMenu.Items.Add(_trayStopMenuItem);
            _trayMenu.Items.Add(new ToolStripSeparator());
            _trayMenu.Items.Add(exitItem);

            _trayIcon = new NotifyIcon
            {
                Icon = _appIcon ?? SystemIcons.Application,
                Visible = true,
                Text = "IPP Server",
                ContextMenuStrip = _trayMenu
            };
            _trayIcon.DoubleClick += (_, _) => ShowMainWindow();
            UpdateTrayMenuState();
        }

        private void UpdateTrayMenuState()
        {
            if (_trayStartMenuItem == null || _trayStopMenuItem == null)
            {
                return;
            }
            var hostRunning = _host != null;
            var ippRunning = hostRunning && (_host?.IsIppServiceEnabled ?? false);
            _trayStartMenuItem.Enabled = !hostRunning || !ippRunning;
            _trayStopMenuItem.Enabled = hostRunning && ippRunning;
        }

        private void ShowMainWindow()
        {
            Show();
            WindowState = FormWindowState.Normal;
            Activate();
        }

        private void HideToTray(bool silent = false)
        {
            if (_trayIcon == null)
            {
                return;
            }

            Hide();
            _trayIcon.Visible = true;

            if (!silent && !_trayBalloonShown)
            {
                _trayIcon.ShowBalloonTip(1500, "IPP Server", "程序已最小化到托盘，双击图标可重新打开。", ToolTipIcon.Info);
                _trayBalloonShown = true;
            }
        }

        private void ExitApplication()
        {
            _trayIcon.Visible = false;
            Close();
        }

        private void UpdateAutoRunRegistration(bool enabled)
        {
            try
            {
                using var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", writable: true)
                                ?? Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
                if (key == null)
                {
                    return;
                }

                if (enabled)
                {
                    var exePath = $"\"{Application.ExecutablePath}\" --autorun";
                    key.SetValue(AutoRunRegistryValue, exePath);
                }
                else
                {
                    key.DeleteValue(AutoRunRegistryValue, false);
                }
            }
            catch (Exception ex)
            {
                AppendLog($"更新自启动设置失败：{ex.Message}");
            }
        }

        private void LoadApplicationIcon()
        {
            try
            {
                var assembly = Assembly.GetExecutingAssembly();
                var resourceName = assembly.GetManifestResourceNames()
                    .FirstOrDefault(name => name.EndsWith(".server.ico", StringComparison.OrdinalIgnoreCase));

                if (!string.IsNullOrEmpty(resourceName))
                {
                    using var stream = assembly.GetManifestResourceStream(resourceName);
                    if (stream != null)
                    {
                        _appIcon = new Icon(stream);
                        Icon = (Icon)_appIcon.Clone();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"加载图标失败：{ex}");
            }

            Icon ??= SystemIcons.Application;
        }

        /// <summary>
        /// 更新TCP打印机防火墙规则（使用单条规则管理所有TCP端口）
        /// </summary>
        private void UpdateTcpFirewallRules()
        {
            try
            {
                if (_tcpTasks == null || _tcpTasks.Count == 0)
                {
                    // 如果没有TCP任务，删除TCP防火墙规则
                    FirewallManager.RemoveTcpFirewallRule(AppendLog);
                    return;
                }

                // 获取所有TCP任务的端口列表（只包含已配置打印机的任务）
                IEnumerable<int> ports = _tcpTasks
                    .Where(t => !string.IsNullOrWhiteSpace(t.PrinterName) && t.Port > 0)
                    .Select(t => t.Port)
                    .Distinct();

                // 更新防火墙规则（单条规则包含所有端口）
                FirewallManager.UpdateTcpFirewallRule(ports, AppendLog);
            }
            catch (Exception ex)
            {
                AppendLog($"更新TCP防火墙规则时发生错误：{ex.Message}");
            }
        }

        /// <summary>
        /// 确保指定端口的防火墙规则已添加，如果端口改变则删除旧规则
        /// </summary>
        /// <param name="currentPort">当前端口号</param>
        /// <param name="oldPort">旧端口号（如果为null或与当前端口相同则忽略）</param>
        private void EnsureFirewallRuleForPort(int currentPort, int? oldPort = null)
        {
            if (currentPort < 1 || currentPort > 65535)
            {
                return;
            }

            // 检查是否以管理员权限运行
            if (!FirewallManager.IsRunningAsAdministrator())
            {
                // 如果不是管理员权限，提示用户
                var oldPortInfo = oldPort.HasValue && oldPort.Value > 0 && oldPort.Value != currentPort
                    ? $"\n旧端口：{oldPort.Value}\n"
                    : "";
                
                AppendLog("提示：未以管理员权限运行，无法自动管理防火墙规则。");
                AppendLog($"当前端口：{currentPort}{oldPortInfo}");
                
                if (oldPort.HasValue && oldPort.Value > 0 && oldPort.Value != currentPort)
                {
                    AppendLog($"请手动删除旧端口 {oldPort.Value} 的防火墙规则，并添加端口 {currentPort} 的入站规则。");
                }
                else
                {
                    AppendLog($"请手动在Windows防火墙中开放端口 {currentPort} 的入站规则。");
                }
                return;
            }

            // 如果端口改变，切换防火墙规则；否则只确保当前端口规则存在
            try
            {
                if (oldPort.HasValue && oldPort.Value > 0 && oldPort.Value != currentPort)
                {
                    // 端口改变：删除旧规则，添加新规则
                    FirewallManager.SwitchFirewallRule(currentPort, oldPort, AppendLog);
                }
                else
                {
                    // 端口未改变：只确保当前端口规则存在
                    FirewallManager.EnsureFirewallRule(currentPort, AppendLog);
                }
            }
            catch (Exception ex)
            {
                AppendLog($"管理防火墙规则时发生错误：{ex.Message}");
            }
        }

        private void InitializeRestrictionTab()
        {
            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 3,
                ColumnCount = 1,
                Padding = new Padding(8)
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 120));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 50));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 50));

            // 顶部：总开关和模式选择
            layout.Controls.Add(CreateRestrictionHeaderPanel(), 0, 0);
            
            // 中间：IP规则管理
            layout.Controls.Add(CreateIpRulesPanel(), 0, 1);
            
            // 底部：MAC规则管理
            layout.Controls.Add(CreateMacRulesPanel(), 0, 2);

            _restrictionTab.Padding = new Padding(3);
            _restrictionTab.Controls.Add(layout);
            _tabControl.TabPages.Add(_restrictionTab);
        }

        private string GetVersionDisplayText()
        {
            try
            {
                return Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "未知";
            }
            catch
            {
                return "未知";
            }
        }

        private Control CreateRestrictionHeaderPanel()
        {
            var panel = new GroupBox
            {
                Text = "IP/MAC地址限制设置",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 3,
                ColumnCount = 2,
                Padding = new Padding(10)
            };
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 200));
            layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 35));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 35));
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

            // 启用限制开关
            _enableRestrictionCheckBox.Text = "启用IP/MAC地址限制";
            _enableRestrictionCheckBox.AutoSize = true;
            _enableRestrictionCheckBox.CheckedChanged += (_, _) =>
            {
                if (_initializingOptions || _settings == null)
                {
                    return;
                }
                UpdateRestrictionControlsState();
                PersistSettingsSilently();
            };
            layout.Controls.Add(_enableRestrictionCheckBox, 0, 0);
            layout.SetColumnSpan(_enableRestrictionCheckBox, 2);

            // 模式选择
            var modeLabel = new Label
            {
                Text = "限制模式：",
                AutoSize = true,
                TextAlign = System.Drawing.ContentAlignment.MiddleLeft
            };
            layout.Controls.Add(modeLabel, 0, 1);

            var modePanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight,
                AutoSize = true
            };
            _blacklistRadioButton.Text = "黑名单（禁止列表中的地址）";
            _blacklistRadioButton.AutoSize = true;
            _blacklistRadioButton.Checked = true;
            _blacklistRadioButton.CheckedChanged += (_, _) =>
            {
                if (_initializingOptions || _settings == null)
                {
                    return;
                }
                PersistSettingsSilently();
            };
            modePanel.Controls.Add(_blacklistRadioButton);

            _whitelistRadioButton.Text = "白名单（仅允许列表中的地址）";
            _whitelistRadioButton.AutoSize = true;
            _whitelistRadioButton.CheckedChanged += (_, _) =>
            {
                if (_initializingOptions || _settings == null)
                {
                    return;
                }
                PersistSettingsSilently();
            };
            modePanel.Controls.Add(_whitelistRadioButton);
            layout.Controls.Add(modePanel, 1, 1);

            panel.Controls.Add(layout);
            return panel;
        }

        private Control CreateIpRulesPanel()
        {
            var panel = new GroupBox
            {
                Text = "IP地址规则",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                ColumnCount = 1
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));

            // IP规则列表
            _ipRulesGrid.Dock = DockStyle.Fill;
            _ipRulesGrid.AutoGenerateColumns = false;
            _ipRulesGrid.AllowUserToAddRows = false;
            _ipRulesGrid.AllowUserToDeleteRows = false;
            _ipRulesGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            _ipRulesGrid.ReadOnly = true;
            _ipRulesGrid.BorderStyle = BorderStyle.FixedSingle;
            _ipRulesGrid.BackgroundColor = System.Drawing.Color.White;
            _ipRulesGrid.GridColor = System.Drawing.Color.LightGray;
            
            // 设置默认单元格样式
            _ipRulesGrid.DefaultCellStyle.BackColor = System.Drawing.Color.White;
            _ipRulesGrid.DefaultCellStyle.ForeColor = System.Drawing.Color.Black;
            _ipRulesGrid.DefaultCellStyle.SelectionBackColor = System.Drawing.Color.FromArgb(0, 120, 215);
            _ipRulesGrid.DefaultCellStyle.SelectionForeColor = System.Drawing.Color.White;
            _ipRulesGrid.DefaultCellStyle.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F);
            
            // 设置表头样式
            _ipRulesGrid.ColumnHeadersDefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(240, 240, 240);
            _ipRulesGrid.ColumnHeadersDefaultCellStyle.ForeColor = System.Drawing.Color.Black;
            _ipRulesGrid.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, System.Drawing.FontStyle.Bold);
            _ipRulesGrid.EnableHeadersVisualStyles = false;
            
            _ipRulesGrid.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "序号",
                Width = 60,
                ReadOnly = true,
                DefaultCellStyle = new DataGridViewCellStyle
                {
                    BackColor = System.Drawing.Color.White,
                    ForeColor = System.Drawing.Color.Black,
                    Alignment = DataGridViewContentAlignment.MiddleCenter
                }
            });
            _ipRulesGrid.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "IP规则",
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
                ReadOnly = true,
                DataPropertyName = "", // 空字符串表示绑定到列表项本身
                DefaultCellStyle = new DataGridViewCellStyle
                {
                    BackColor = System.Drawing.Color.White,
                    ForeColor = System.Drawing.Color.Black,
                    Alignment = DataGridViewContentAlignment.MiddleLeft,
                    Padding = new Padding(5, 0, 5, 0)
                }
            });
            _ipRulesGrid.DataSource = _ipRulesList;
            _ipRulesGrid.CellFormatting += (sender, e) =>
            {
                if (e.ColumnIndex == 0 && e.RowIndex >= 0)
                {
                    // 序号列
                    e.Value = (e.RowIndex + 1).ToString();
                    e.FormattingApplied = true;
                }
                else if (e.ColumnIndex == 1 && e.RowIndex >= 0 && e.RowIndex < _ipRulesList.Count)
                {
                    // IP规则列 - 直接显示列表项的值
                    e.Value = _ipRulesList[e.RowIndex];
                    e.FormattingApplied = true;
                }
            };
            layout.Controls.Add(_ipRulesGrid, 0, 0);

            // 按钮面板
            var buttonPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight
            };
            _addIpRuleButton.Text = "添加IP规则";
            _addIpRuleButton.AutoSize = false;
            _addIpRuleButton.Width = 120;
            _addIpRuleButton.Height = 30;
            _addIpRuleButton.Click += (_, _) => AddIpRule();
            buttonPanel.Controls.Add(_addIpRuleButton);

            _removeIpRuleButton.Text = "删除选中";
            _removeIpRuleButton.AutoSize = false;
            _removeIpRuleButton.Width = 120;
            _removeIpRuleButton.Height = 30;
            _removeIpRuleButton.Click += (_, _) => RemoveIpRule();
            buttonPanel.Controls.Add(_removeIpRuleButton);
            layout.Controls.Add(buttonPanel, 0, 1);

            panel.Controls.Add(layout);
            return panel;
        }

        private Control CreateMacRulesPanel()
        {
            var panel = new GroupBox
            {
                Text = "MAC地址规则",
                Dock = DockStyle.Fill
            };

            var layout = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                RowCount = 2,
                ColumnCount = 1
            };
            layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
            layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40));

            // MAC规则列表
            _macRulesGrid.Dock = DockStyle.Fill;
            _macRulesGrid.AutoGenerateColumns = false;
            _macRulesGrid.AllowUserToAddRows = false;
            _macRulesGrid.AllowUserToDeleteRows = false;
            _macRulesGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            _macRulesGrid.ReadOnly = true;
            _macRulesGrid.BorderStyle = BorderStyle.FixedSingle;
            _macRulesGrid.BackgroundColor = System.Drawing.Color.White;
            _macRulesGrid.GridColor = System.Drawing.Color.LightGray;
            
            // 设置默认单元格样式
            _macRulesGrid.DefaultCellStyle.BackColor = System.Drawing.Color.White;
            _macRulesGrid.DefaultCellStyle.ForeColor = System.Drawing.Color.Black;
            _macRulesGrid.DefaultCellStyle.SelectionBackColor = System.Drawing.Color.FromArgb(0, 120, 215);
            _macRulesGrid.DefaultCellStyle.SelectionForeColor = System.Drawing.Color.White;
            _macRulesGrid.DefaultCellStyle.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F);
            
            // 设置表头样式
            _macRulesGrid.ColumnHeadersDefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(240, 240, 240);
            _macRulesGrid.ColumnHeadersDefaultCellStyle.ForeColor = System.Drawing.Color.Black;
            _macRulesGrid.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F, System.Drawing.FontStyle.Bold);
            _macRulesGrid.EnableHeadersVisualStyles = false;
            
            _macRulesGrid.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "序号",
                Width = 60,
                ReadOnly = true,
                DefaultCellStyle = new DataGridViewCellStyle
                {
                    BackColor = System.Drawing.Color.White,
                    ForeColor = System.Drawing.Color.Black,
                    Alignment = DataGridViewContentAlignment.MiddleCenter
                }
            });
            _macRulesGrid.Columns.Add(new DataGridViewTextBoxColumn
            {
                HeaderText = "MAC规则",
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
                ReadOnly = true,
                DataPropertyName = "", // 空字符串表示绑定到列表项本身
                DefaultCellStyle = new DataGridViewCellStyle
                {
                    BackColor = System.Drawing.Color.White,
                    ForeColor = System.Drawing.Color.Black,
                    Alignment = DataGridViewContentAlignment.MiddleLeft,
                    Padding = new Padding(5, 0, 5, 0)
                }
            });
            _macRulesGrid.DataSource = _macRulesList;
            _macRulesGrid.CellFormatting += (sender, e) =>
            {
                if (e.ColumnIndex == 0 && e.RowIndex >= 0)
                {
                    // 序号列
                    e.Value = (e.RowIndex + 1).ToString();
                    e.FormattingApplied = true;
                }
                else if (e.ColumnIndex == 1 && e.RowIndex >= 0 && e.RowIndex < _macRulesList.Count)
                {
                    // MAC规则列 - 直接显示列表项的值
                    e.Value = _macRulesList[e.RowIndex];
                    e.FormattingApplied = true;
                }
            };
            layout.Controls.Add(_macRulesGrid, 0, 0);

            // 按钮面板
            var buttonPanel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                FlowDirection = FlowDirection.LeftToRight
            };
            _addMacRuleButton.Text = "添加MAC规则";
            _addMacRuleButton.AutoSize = false;
            _addMacRuleButton.Width = 120;
            _addMacRuleButton.Height = 30;
            _addMacRuleButton.Click += (_, _) => AddMacRule();
            buttonPanel.Controls.Add(_addMacRuleButton);

            _removeMacRuleButton.Text = "删除选中";
            _removeMacRuleButton.AutoSize = false;
            _removeMacRuleButton.Width = 120;
            _removeMacRuleButton.Height = 30;
            _removeMacRuleButton.Click += (_, _) => RemoveMacRule();
            buttonPanel.Controls.Add(_removeMacRuleButton);
            layout.Controls.Add(buttonPanel, 0, 1);

            panel.Controls.Add(layout);
            return panel;
        }

        private void UpdateRestrictionControlsState()
        {
            var enabled = _enableRestrictionCheckBox.Checked;
            _whitelistRadioButton.Enabled = enabled;
            _blacklistRadioButton.Enabled = enabled;
            _ipRulesGrid.Enabled = enabled;
            _macRulesGrid.Enabled = enabled;
            _addIpRuleButton.Enabled = enabled;
            _removeIpRuleButton.Enabled = enabled;
            _addMacRuleButton.Enabled = enabled;
            _removeMacRuleButton.Enabled = enabled;
        }

        private void AddIpRule()
        {
            using (var dialog = new Form
            {
                Text = "添加IP规则",
                Width = 500,
                Height = 200,
                FormBorderStyle = FormBorderStyle.FixedDialog,
                MaximizeBox = false,
                MinimizeBox = false,
                StartPosition = FormStartPosition.CenterParent
            })
            {
                var layout = new TableLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    RowCount = 3,
                    ColumnCount = 1,
                    Padding = new Padding(10)
                };
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 30));
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 30));
                layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

                var label = new Label
                {
                    Text = "请输入IP规则（支持单个IP、CIDR网段如192.168.1.0/24、IP范围如192.168.1.1-192.168.1.100）：",
                    AutoSize = true,
                    Dock = DockStyle.Fill
                };
                layout.Controls.Add(label, 0, 0);

                var textBox = new TextBox
                {
                    Dock = DockStyle.Fill,
                    Font = new System.Drawing.Font("Consolas", 9)
                };
                layout.Controls.Add(textBox, 0, 1);

                var buttonPanel = new FlowLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    FlowDirection = FlowDirection.RightToLeft
                };
                var okButton = new Button { Text = "确定", DialogResult = DialogResult.OK, Width = 80 };
                var cancelButton = new Button { Text = "取消", DialogResult = DialogResult.Cancel, Width = 80 };
                buttonPanel.Controls.Add(okButton);
                buttonPanel.Controls.Add(cancelButton);
                layout.Controls.Add(buttonPanel, 0, 2);

                dialog.Controls.Add(layout);
                dialog.AcceptButton = okButton;
                dialog.CancelButton = cancelButton;

                if (dialog.ShowDialog(this) == DialogResult.OK)
                {
                    var rule = textBox.Text.Trim();
                    if (string.IsNullOrWhiteSpace(rule))
                    {
                        MessageBox.Show("IP规则不能为空。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    if (!Configuration.IpMacValidator.ValidateIpRule(rule, out var errorMessage))
                    {
                        MessageBox.Show($"IP规则格式无效：{errorMessage}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    if (_ipRulesList.Contains(rule))
                    {
                        MessageBox.Show("该IP规则已存在。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }

                    _ipRulesList.Add(rule);
                    PersistSettingsSilently();
                    AppendLog($"已添加IP规则：{rule}");
                }
            }
        }

        private void RemoveIpRule()
        {
            if (_ipRulesGrid.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选择要删除的IP规则。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var selectedIndex = _ipRulesGrid.SelectedRows[0].Index;
            if (selectedIndex >= 0 && selectedIndex < _ipRulesList.Count)
            {
                var rule = _ipRulesList[selectedIndex];
                if (MessageBox.Show($"确定要删除IP规则：{rule}？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    _ipRulesList.RemoveAt(selectedIndex);
                    PersistSettingsSilently();
                    AppendLog($"已删除IP规则：{rule}");
                }
            }
        }

        private void AddMacRule()
        {
            using (var dialog = new Form
            {
                Text = "添加MAC规则",
                Width = 500,
                Height = 200,
                FormBorderStyle = FormBorderStyle.FixedDialog,
                MaximizeBox = false,
                MinimizeBox = false,
                StartPosition = FormStartPosition.CenterParent
            })
            {
                var layout = new TableLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    RowCount = 3,
                    ColumnCount = 1,
                    Padding = new Padding(10)
                };
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 30));
                layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 30));
                layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));

                var label = new Label
                {
                    Text = "请输入MAC规则（支持完整MAC地址如00:11:22:33:44:55或通配符如00:11:22:*:*:*）：",
                    AutoSize = true,
                    Dock = DockStyle.Fill
                };
                layout.Controls.Add(label, 0, 0);

                var textBox = new TextBox
                {
                    Dock = DockStyle.Fill,
                    Font = new System.Drawing.Font("Consolas", 9),
                    Text = "00:11:22:33:44:55"
                };
                layout.Controls.Add(textBox, 0, 1);

                var buttonPanel = new FlowLayoutPanel
                {
                    Dock = DockStyle.Fill,
                    FlowDirection = FlowDirection.RightToLeft
                };
                var okButton = new Button { Text = "确定", DialogResult = DialogResult.OK, Width = 80 };
                var cancelButton = new Button { Text = "取消", DialogResult = DialogResult.Cancel, Width = 80 };
                buttonPanel.Controls.Add(okButton);
                buttonPanel.Controls.Add(cancelButton);
                layout.Controls.Add(buttonPanel, 0, 2);

                dialog.Controls.Add(layout);
                dialog.AcceptButton = okButton;
                dialog.CancelButton = cancelButton;

                if (dialog.ShowDialog(this) == DialogResult.OK)
                {
                    var rule = textBox.Text.Trim();
                    if (string.IsNullOrWhiteSpace(rule))
                    {
                        MessageBox.Show("MAC规则不能为空。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    if (!Configuration.IpMacValidator.ValidateMacRule(rule, out var errorMessage))
                    {
                        MessageBox.Show($"MAC规则格式无效：{errorMessage}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    // 标准化MAC地址格式（支持多种输入格式）
                    rule = Configuration.IpMacValidator.NormalizeMacAddress(rule);
                    if (rule == null)
                    {
                        MessageBox.Show("MAC规则格式无效，无法标准化。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    if (_macRulesList.Contains(rule))
                    {
                        MessageBox.Show("该MAC规则已存在。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }

                    _macRulesList.Add(rule);
                    PersistSettingsSilently();
                    AppendLog($"已添加MAC规则：{rule}");
                }
            }
        }

        private void RemoveMacRule()
        {
            if (_macRulesGrid.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选择要删除的MAC规则。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var selectedIndex = _macRulesGrid.SelectedRows[0].Index;
            if (selectedIndex >= 0 && selectedIndex < _macRulesList.Count)
            {
                var rule = _macRulesList[selectedIndex];
                if (MessageBox.Show($"确定要删除MAC规则：{rule}？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    _macRulesList.RemoveAt(selectedIndex);
                    PersistSettingsSilently();
                    AppendLog($"已删除MAC规则：{rule}");
                }
            }
        }
    }
}

